Restore: fix performance regression on .NET Core 2.1+ #2430
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Resolve NuGet/Home#7314.
The core problem with the original code is that it forces a buffer to be flushed synchronously rather than asynchronously (and, actually worse than that, as a sync-over-async operation, meaning it’s performing an asynchronous operation and then blocking waiting for it to complete). That would occur as part of the Seek, or if the validation wasn’t there, as part of Dispose’ing the FileStream, both synchronous operations.
The right fix would be to add an “await FileStream.FlushAsync();” before doing the seeking/validation/closing. That flush would ensure that the buffer is empty when Seek/Dispose/etc. are closed, so there’s nothing more to flush. However, there’s a bug in FlushAsync that’s causing it to also do the key part of the flush synchronously as well.
So, the workaround is to avoid buffering, such that nothing needs to be flushed as part of Seek/Dispose. That’s what bufferSize=1 does.
However, the concern expressed was that disabling that buffering would avoid this problem for the writing but would slow down the reading/validation. So, the fix splits it into two streams: one used for writing with buffering disabled, and then one used for reading that has buffering enabled still.
CC @rrelyea