Skip to content

Allow use of a default MemoryPoolFeature on ConnectionContext #18579

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 15, 2020

Conversation

Ninds
Copy link
Contributor

@Ninds Ninds commented Jan 25, 2020

davidfowl/BedrockFramework#65

This facilitates the use of other Transports other than sockets.
When kestrel bound to MemoryTransport (Bedrock davidfowl/BedrockFramework#65) a NullReferenceException is thrown since the MemoryPoolFeature is not set on the ConnectionContext set in that Transport

Summary of the changes (Less than 80 chars)

  • Detail 1
  • Detail 2

Addresses #bugnumber (in this specific format)

@@ -33,7 +34,7 @@ public Task OnConnectionAsync(ConnectionContext connectionContext)
Protocols = _protocols,
ServiceContext = _serviceContext,
ConnectionFeatures = connectionContext.Features,
MemoryPool = memoryPoolFeature.MemoryPool,
MemoryPool = memoryPoolFeature?.MemoryPool ?? System.Buffers.MemoryPool<byte>.Shared,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should let this be null (without the null ref that is). Don't fallback to the default memory pool though. If that breaks we should fix those places that use the pool directly.

We also need to add a test for this to make sure it doesn't break.

Copy link
Contributor Author

@Ninds Ninds Jan 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. So leave it as
memoryPool = memoryPoolFeature?.MemoryPool
and solve any side-effects later on in the code path where they occur ?
This could be tested with MemoryEndPoint.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

Copy link
Contributor Author

@Ninds Ninds Jan 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the MemoryPoolFeature accessible in any middleware wired up to Ketsrel through the HttpConnectionContext ? If so, any middleware assuming it's presence will break when the endpoint in the instance of Kestrel is changed to a non-socket based endpoint like MemoryEndPoint.
Consider the scenario where my kestrel based app,, is switching to MemoryEndpoint for testing purposes and at the same time I am retrieving the MemoryPoolFeature in my middleware making use of it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes but this isn't a required feature so I'd like to understand the places that rely on it being non-null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not include ?? MemoryPool<byte>.Shared here? The same thing will happen implicitly later when we new up PipeOptions.

Yes but this isn't a required feature so I'd like to understand the places that rely on it being non-null.

By adding ?? MemoryPool<byte>.Shared, the middleware is no longer relying on the feature.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What middleware is that? This is a specific middleware (the HTTP middleware) that relies on it currently. The TLS middleware already handles this.

Before doing this fix I just want to understand what code in the HTTP layer relies on this being non-null. I have no problem putting it back.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point? Like you say, this is the HTTP middleware. By adding this, there would be no code in the HTTP layer that relies on this being non-null.

Copy link
Contributor Author

@Ninds Ninds Jan 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just want to understand what code in the HTTP layer relies on this being non-null
I have no problem putting it back

Would I be right in thinking that these two actions are independent and that one is not a blocker for the other ? I guess the first can be achieved by setting the MemoryPool to null and seeing where the Tests fail ( I did this and there were at least 13 failures)
and the second can be done to introduce the fix but without any significant hindrance to carrying out the first (given the change is trivial) ?

if on the other hand :

I just want to understand what code in the HTTP layer relies on this being non-null

is likely to lead to a different outcome then that's a different matter.

A bit of context (no pun intended), the MemoryPool was set in the ConnectionContext when binding to a socket but was not set in the ConnectionContext when binding to a (Bedrock) MemoryEndpoint. In both cases ConnectionContext was intended to pushed down the HttpMiddleware.

Is the Transport factory obliged to set the MemoryPool ? If so, how could it be enforced ? If not then I guess provision of a fallback default is mandatory and why is it set in the ConnectionContext in kestrel ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@halter73

What's the point? Like you say, this is the HTTP middleware. By adding this, there would be no code in the HTTP layer that relies on this being non-null.

The transport isn't required to set a pool and the IMemoryPoolFeature isn't required. Kestrel needs to take that into account. Kestrel can also polyfill by defaulting to using a pool but I have 2 concerns:

  1. We don't have an understanding where it does that. I'd like to understand before making assumptions.
  2. We probably want to use the SlabMemoryPool and not the default memory pool in the places where we explicitly allocate.

@Ninds

Would I be right in thinking that these two actions are independent and that one is not a blocker for the other ? I guess the first can be achieved by setting the MemoryPool to null and seeing where the Tests fail ( I did this and there were at least 13 failures)
and the second can be done to introduce the fix but without any significant hindrance to carrying out the first (given the change is trivial) ?

The code change is trivial, measuring the impact isn't without understanding what parts of the code rely on this instance.

Is the Transport factory obliged to set the MemoryPool ? If so, how could it be enforced ? If not then I guess provision of a fallback default is mandatory and why is it set in the ConnectionContext in kestrel ?

Features can be optional, it's part of the system. It's not set on the ConnectionContext, it's just an optional feature that middleware may use if it exists.

@@ -43,5 +44,6 @@ public Task OnConnectionAsync(ConnectionContext connectionContext)

return connection.ProcessRequestsAsync(_application);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: remove this empty line.

@analogrelay analogrelay added this to the 5.0.0-preview1 milestone Jan 27, 2020
@analogrelay
Copy link
Contributor

Sounds like we're waiting for author feedback on the proposal to continue to let the memory pool be null but change our consumption points to use a default. Correct? Trying to identify what we need to do to get this PR resolved/closed.

@Ninds
Copy link
Contributor Author

Ninds commented Feb 21, 2020

I will try this weekend to figure out where the memorypool is being used.

@shirhatti
Copy link
Contributor

@davidfowl Do you still want this?

@davidfowl
Copy link
Member

Yes.

@halter73
Copy link
Member

@davidfowl Are you fine with this as is?

@davidfowl
Copy link
Member

At this point the only change I would make is to use the SlabPool.

@halter73
Copy link
Member

halter73 commented Apr 15, 2020

At this point the only change I would make is to use the SlabPool.

I think that makes more sense. I figured that given a transport that doesn't implement the IMemoryPoolFeature, we don't care about using the most optimal pool. But then again, why not?

We can just change System.Buffers.MemoryPool<byte>.Shared to SlabMemoryPoolFactory.Create(). We should also change Http3ConnectionMiddleware to do the same thing.

Edit: SlabMemoryPool is shared source, so we'll also need to add <Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" /> to Kestrel.Core.csproj.

@halter73 halter73 self-requested a review April 15, 2020 21:07
@halter73
Copy link
Member

Looking at this more, I think changing to use the SlabMemoryPool in Kestrel.Core will be very difficult. There are a bunch of test projects that have InternalsVisibleTo access to both Kestrel.Core internals and the internals to one of the transports that also use the SlabMemoryPool as shared source.

This means adding the SlabMemoryPool to Kestrel.Core causes a bunch of type conflicts 😢

@halter73
Copy link
Member

After more discussion with @davidfowl, it looks like we're taking this as is 😄

@halter73 halter73 closed this Apr 15, 2020
@halter73 halter73 reopened this Apr 15, 2020
Ninds and others added 2 commits April 15, 2020 15:05
…set on ConnectionContext

This facilitates the use of other Transports other than sockets.
When kestrel bound to MemoryTransport (Bedrock davidfowl/BedrockFramework#65) a NullReferenceException is thrown since the MemoryPoolFeature is not set on the ConnectionContext set in that Transport
@dnfclas
Copy link

dnfclas commented Apr 15, 2020

CLA assistant check
All CLA requirements met.

@halter73
Copy link
Member

@dotnet/dnceng Is the CLA necessary for such a small change? I don't know why the bot is only triggering now.

@pranavkm pranavkm removed this from the 5.0.0-preview2 milestone Apr 15, 2020
@pranavkm pranavkm added this to the 5.0.0-preview4 milestone Apr 15, 2020
@halter73 halter73 merged commit f908247 into dotnet:master May 15, 2020
@halter73
Copy link
Member

Thanks @Ninds!

@Ninds Ninds deleted the master branch February 3, 2022 21:52
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants