Skip to content

Conversation

@sebastienros
Copy link
Member

@sebastienros sebastienros commented Aug 25, 2021

GetFakeMemory() can throw an exception if sizeHint is greater than MaxPoolSize. The default pool is PinnedBlockMemoryPool with a max size of 4096.

Fixes #30364

@sebastienros
Copy link
Member Author

Once approved I will start the process of backporting it to 3.1 and 5.0.

@halter73
Copy link
Member

Can we add some regression tests for this?

@sebastienros
Copy link
Member Author

Updated with feedback and unit tests.
I also used the repro code provided with the issue to confirm the bug, then tried these changes to confirm it was fixing it.

@davidfowl
Copy link
Member

Wouldn't it be simpler to support a null fake memory owner and just use ArrayPool.Shared?

@halter73
Copy link
Member

Wouldn't it be simpler to support a null fake memory owner and just use ArrayPool.Shared?

What's the benefit? Wouldn't you need to special case returning the array in Dispose() in that case?

@sebastienros
Copy link
Member Author

I would understand @davidfowl 's suggestion as replacing _fakeMemoryOwner by byte[] _fakeMemory which would always come from the ArrayPool.Shared if set, and then returned in Dispose. So as single source. But I don't know why it was using _memoryPool before vs. the array pool.

@davidfowl
Copy link
Member

What's the benefit? Wouldn't you need to special case returning the array in Dispose() in that case?

This code originally came from https://source.dot.net/#System.IO.Pipelines/System/IO/Pipelines/BufferSegment.cs,56 which handles this in a much nicer way IMO.

@halter73
Copy link
Member

What's nicer about BufferSegment's way of doing it?

@davidfowl
Copy link
Member

It's isolated in the buffer segment and doesn't allocate another kind of IMemoryOwner<byte>.

@sebastienros
Copy link
Member Author

I am trying to implement what I think you meant ... hope it's worth it. Will do it in a separate branch as I am very not sure about the end result.

@sebastienros
Copy link
Member Author

@davidfowl is this what you meant?

5de377a

@halter73
Copy link
Member

halter73 commented Sep 1, 2021

@davidfowl is this what you meant?

I'll try channeling @davidfowl. Allocating a FakeMemory isn't any better than allocating "another kind of IMemoryOwner<byte>.". This allocates even more than before in the case where the _memoryPool is used in FakeMemory.

If FakeMemory was pooled like BufferSegments are in System.IO.Pipelines, this wouldn't introduce a new allocation, but that's not the case here. We shouldn't bother pooling FakeMemory since this would only get allocated when a connection/request is aborted meaning the output producer itself will never be pooled at this point.

Instead the suggestion is to put separate IMemoryOwner<byte>? and byte[]? fields diretly in the output producers that are never both set at the same time similar to BufferSegment.


Now I'm going to speak as myself again. This seems like a lot of work to avoid a single extra allocation for aborted requests where the writer needs large buffers. This is a pretty rare scenario that isn't going to be very efficient to begin with. That said, it's not that much extra work I guess.

@sebastienros
Copy link
Member Author

@halter73 now I understand the comment, thanks.

@sebastienros
Copy link
Member Author

updated

@sebastienros
Copy link
Member Author

@davidfowl are the changes what you expected?

@sebastienros sebastienros enabled auto-merge (squash) September 7, 2021 15:03
@sebastienros sebastienros merged commit 764ac0a into main Sep 7, 2021
@sebastienros sebastienros deleted the sebros/fakememory branch September 7, 2021 15:11
@sebastienros
Copy link
Member Author

/backport to release/6.0

@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2021

@sebastienros
Copy link
Member Author

/backport to release/5.0

@github-actions
Copy link
Contributor

@github-actions
Copy link
Contributor

@sebastienros backporting to release/5.0 failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch

Applying: Use ArrayPool as SlabMemoryPool fallback
Applying: Fix comments
Applying: Typos
Applying: Support increase buffer size
Applying: Add function tests, rename argument
error: sha1 information is lacking or useless (src/Servers/Kestrel/Core/src/Internal/Http/Http1OutputProducer.cs).
error: could not build fake ancestor
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0005 Add function tests, rename argument
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

sebastienros added a commit that referenced this pull request Sep 15, 2021
@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.

ResponseCachingMiddleware: exception "Cannot allocate more than 4096 bytes in a single buffer" when a client disconnects

6 participants