Amortize Stream Costs
This commit is contained in:
parent
349af50977
commit
f5e45accac
|
|
@ -57,6 +57,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
internal FrameRequestStream _requestBody;
|
||||
internal FrameResponseStream _responseBody;
|
||||
internal FrameDuplexStream _duplexStream;
|
||||
|
||||
protected bool _responseStarted;
|
||||
protected bool _keepAlive;
|
||||
|
|
@ -86,6 +87,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
_localEndPoint = localEndPoint;
|
||||
_prepareRequest = prepareRequest;
|
||||
_pathBase = context.ServerAddress.PathBase;
|
||||
_requestBody = new FrameRequestStream();
|
||||
_responseBody = new FrameResponseStream(this);
|
||||
_duplexStream = new FrameDuplexStream(_requestBody, _responseBody);
|
||||
|
||||
FrameControl = this;
|
||||
Reset();
|
||||
|
|
|
|||
|
|
@ -64,11 +64,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
var messageBody = MessageBody.For(HttpVersion, _requestHeaders, this);
|
||||
_keepAlive = messageBody.RequestKeepAlive;
|
||||
_requestBody = new FrameRequestStream(messageBody);
|
||||
RequestBody = _requestBody;
|
||||
_responseBody = new FrameResponseStream(this);
|
||||
ResponseBody = _responseBody;
|
||||
DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
|
||||
RequestBody = _requestBody.StartAcceptingReads(messageBody);
|
||||
ResponseBody = _responseBody.StartAcceptingWrites();
|
||||
DuplexStream = _duplexStream;
|
||||
|
||||
_abortedCts = null;
|
||||
_manuallySetRequestAbortToken = null;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
public class FrameRequestStream : Stream
|
||||
{
|
||||
private readonly MessageBody _body;
|
||||
private MessageBody _body;
|
||||
private StreamState _state;
|
||||
|
||||
public FrameRequestStream(MessageBody body)
|
||||
public FrameRequestStream()
|
||||
{
|
||||
_body = body;
|
||||
_state = StreamState.Closed;
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return true; } }
|
||||
|
|
@ -112,18 +112,30 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Stream StartAcceptingReads(MessageBody body)
|
||||
{
|
||||
// Only start if not aborted
|
||||
if (_state == StreamState.Closed)
|
||||
{
|
||||
_state = StreamState.Open;
|
||||
_body = body;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void StopAcceptingReads()
|
||||
{
|
||||
// Can't use dispose (or close) as can be disposed too early by user code
|
||||
// As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
|
||||
_state = StreamState.Disposed;
|
||||
_state = StreamState.Closed;
|
||||
_body = null;
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
// We don't want to throw an ODE until the app func actually completes.
|
||||
// If the request is aborted, we throw an IOException instead.
|
||||
if (_state != StreamState.Disposed)
|
||||
if (_state != StreamState.Closed)
|
||||
{
|
||||
_state = StreamState.Aborted;
|
||||
}
|
||||
|
|
@ -135,7 +147,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
case StreamState.Open:
|
||||
return;
|
||||
case StreamState.Disposed:
|
||||
case StreamState.Closed:
|
||||
throw new ObjectDisposedException(nameof(FrameRequestStream));
|
||||
case StreamState.Aborted:
|
||||
throw new IOException("The request has been aborted.");
|
||||
|
|
@ -145,7 +157,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
private enum StreamState
|
||||
{
|
||||
Open,
|
||||
Disposed,
|
||||
Closed,
|
||||
Aborted
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
public FrameResponseStream(FrameContext context)
|
||||
{
|
||||
_context = context;
|
||||
_state = StreamState.Closed;
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
|
|
@ -77,18 +78,29 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
return _context.FrameControl.WriteAsync(new ArraySegment<byte>(buffer, offset, count), cancellationToken);
|
||||
}
|
||||
|
||||
public Stream StartAcceptingWrites()
|
||||
{
|
||||
// Only start if not aborted
|
||||
if (_state == StreamState.Closed)
|
||||
{
|
||||
_state = StreamState.Open;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void StopAcceptingWrites()
|
||||
{
|
||||
// Can't use dispose (or close) as can be disposed too early by user code
|
||||
// As exampled in EngineTests.ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
|
||||
_state = StreamState.Disposed;
|
||||
_state = StreamState.Closed;
|
||||
}
|
||||
|
||||
public void Abort()
|
||||
{
|
||||
// We don't want to throw an ODE until the app func actually completes.
|
||||
// If the request is aborted, we throw an IOException instead.
|
||||
if (_state != StreamState.Disposed)
|
||||
if (_state != StreamState.Closed)
|
||||
{
|
||||
_state = StreamState.Aborted;
|
||||
}
|
||||
|
|
@ -100,7 +112,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
case StreamState.Open:
|
||||
return;
|
||||
case StreamState.Disposed:
|
||||
case StreamState.Closed:
|
||||
throw new ObjectDisposedException(nameof(FrameResponseStream));
|
||||
case StreamState.Aborted:
|
||||
throw new IOException("The request has been aborted.");
|
||||
|
|
@ -110,7 +122,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
private enum StreamState
|
||||
{
|
||||
Open,
|
||||
Disposed,
|
||||
Closed,
|
||||
Aborted
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
|||
{
|
||||
var input = new TestInput();
|
||||
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, StringValues>(), input.FrameContext);
|
||||
var stream = new FrameRequestStream(body);
|
||||
var stream = new FrameRequestStream().StartAcceptingReads(body);
|
||||
|
||||
input.Add("Hello", true);
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
|||
{
|
||||
var input = new TestInput();
|
||||
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, StringValues>(), input.FrameContext);
|
||||
var stream = new FrameRequestStream(body);
|
||||
var stream = new FrameRequestStream().StartAcceptingReads(body);
|
||||
|
||||
input.Add("Hello", true);
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
|
|||
{
|
||||
var input = new TestInput();
|
||||
var body = MessageBody.For("HTTP/1.0", new Dictionary<string, StringValues>(), input.FrameContext);
|
||||
var stream = new FrameRequestStream(body);
|
||||
var stream = new FrameRequestStream().StartAcceptingReads(body);
|
||||
|
||||
// Input needs to be greater than 4032 bytes to allocate a block not backed by a slab.
|
||||
var largeInput = new string('a', 8192);
|
||||
|
|
|
|||
Loading…
Reference in New Issue