Don't allocate Exceptions unnecessarily

- Allocate Exceptions in the ReadStart callbacks if necessary instead
  of in UvStreamHandle.
- This also fixes a bug in ListenerSecondary where it should have
  previously been looking at the error code instead of the read count.

#237
This commit is contained in:
Stephen Halter 2015-10-14 17:19:38 -07:00
parent 8e818e3549
commit c809beec18
6 changed files with 28 additions and 36 deletions

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
{
public class Connection : ConnectionContext, IConnectionControl
{
private static readonly Action<UvStreamHandle, int, int, Exception, object> _readCallback = ReadCallback;
private static readonly Action<UvStreamHandle, int, object> _readCallback = ReadCallback;
private static readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
private static long _lastConnectionId;
@ -113,28 +113,34 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
result.Data.Count);
}
private static void ReadCallback(UvStreamHandle handle, int readCount, int errorCode, Exception error, object state)
private static void ReadCallback(UvStreamHandle handle, int status, object state)
{
((Connection)state).OnRead(handle, readCount, errorCode, error);
((Connection)state).OnRead(handle, status);
}
private void OnRead(UvStreamHandle handle, int readCount, int errorCode, Exception error)
private void OnRead(UvStreamHandle handle, int status)
{
var normalRead = readCount != 0 && errorCode == 0;
var normalDone = readCount == 0 && (errorCode == 0 || errorCode == Constants.ECONNRESET || errorCode == Constants.EOF);
var normalRead = status > 0;
var normalDone = status == 0 || status == Constants.ECONNRESET || status == Constants.EOF;
var errorDone = !(normalDone || normalRead);
var readCount = normalRead ? status : 0;
if (normalRead)
{
Log.ConnectionRead(_connectionId, readCount);
}
else if (normalDone || errorDone)
else
{
_socket.ReadStop();
Log.ConnectionReadFin(_connectionId);
}
_rawSocketInput.IncomingComplete(readCount, errorDone ? error : null);
Exception error = null;
if (errorDone)
{
handle.Libuv.Check(status, out error);
}
_rawSocketInput.IncomingComplete(readCount, error);
}
void IConnectionControl.Pause()

View File

@ -61,7 +61,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
DispatchPipe.ReadStart(
(_1, _2, _3) => buf,
(_1, status2, errCode, error2, state2) =>
(_1, status2, state2) =>
{
if (status2 < 0)
{

View File

@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure
void ConnectionStop(long connectionId);
void ConnectionRead(long connectionId, int status);
void ConnectionRead(long connectionId, int count);
void ConnectionPause(long connectionId);

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
private GCHandle _listenVitality;
public Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback;
public Action<UvStreamHandle, int, int, Exception, object> _readCallback;
public Action<UvStreamHandle, int, object> _readCallback;
public object _readState;
private GCHandle _readVitality;
@ -72,13 +72,14 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
public void ReadStart(
Func<UvStreamHandle, int, object, Libuv.uv_buf_t> allocCallback,
Action<UvStreamHandle, int, int, Exception, object> readCallback,
Action<UvStreamHandle, int, object> readCallback,
object state)
{
if (_readVitality.IsAllocated)
{
throw new InvalidOperationException("TODO: ReadStop must be called before ReadStart may be called again");
}
try
{
_allocCallback = allocCallback;
@ -118,7 +119,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
return _uv.try_write(this, new[] { buf }, 1);
}
private static void UvConnectionCb(IntPtr handle, int status)
{
var stream = FromIntPtr<UvStreamHandle>(handle);
@ -137,7 +137,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
}
private static void UvAllocCb(IntPtr handle, int suggested_size, out Libuv.uv_buf_t buf)
{
var stream = FromIntPtr<UvStreamHandle>(handle);
@ -153,22 +152,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Networking
}
}
private static void UvReadCb(IntPtr handle, int nread, ref Libuv.uv_buf_t buf)
private static void UvReadCb(IntPtr handle, int status, ref Libuv.uv_buf_t buf)
{
var stream = FromIntPtr<UvStreamHandle>(handle);
try
{
if (nread < 0)
{
Exception error;
stream._uv.Check(nread, out error);
stream._readCallback(stream, 0, nread, error, stream._readState);
}
else
{
stream._readCallback(stream, nread, 0, null, stream._readState);
}
stream._readCallback(stream, status, stream._readState);
}
catch (Exception ex)
{

View File

@ -113,7 +113,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
connect.Dispose();
clientConnectionPipe.ReadStart(
(_3, cb, _4) => buf,
(_3, status2, errCode, error2, _4) =>
(_3, status2, _4) =>
{
if (status2 == 0)
{
@ -213,7 +213,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
clientConnectionPipe.ReadStart(
(_3, cb, _4) => buf,
(_3, status2, errCode2, error2, _4) =>
(_3, status2, _4) =>
{
if (status2 == 0)
{
@ -226,7 +226,7 @@ namespace Microsoft.AspNet.Server.KestrelTests
var buf2 = loop2.Libuv.buf_init(Marshal.AllocHGlobal(64), 64);
clientConnectionTcp.ReadStart(
(_5, cb, _6) => buf2,
(_5, status3, errCode3, error3, _6) =>
(_5, status3, _6) =>
{
if (status3 == 0)
{

View File

@ -129,7 +129,6 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact]
public async Task SocketCanRead()
{
int bytesRead = 0;
var loop = new UvLoopHandle(_logger);
loop.Init(_uv);
var tcp = new UvTcpHandle(_logger);
@ -145,10 +144,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
var data = Marshal.AllocCoTaskMem(500);
tcp2.ReadStart(
(a, b, c) => _uv.buf_init(data, 500),
(__, nread, errCode, error2, state2) =>
(__, nread, state2) =>
{
bytesRead += nread;
if (nread == 0)
if (nread <= 0)
{
tcp2.Dispose();
}
@ -186,7 +184,6 @@ namespace Microsoft.AspNet.Server.KestrelTests
[Fact]
public async Task SocketCanReadAndWrite()
{
int bytesRead = 0;
var loop = new UvLoopHandle(_logger);
loop.Init(_uv);
var tcp = new UvTcpHandle(_logger);
@ -202,10 +199,9 @@ namespace Microsoft.AspNet.Server.KestrelTests
var data = Marshal.AllocCoTaskMem(500);
tcp2.ReadStart(
(a, b, c) => tcp2.Libuv.buf_init(data, 500),
(__, nread, errCode, error2, state2) =>
(__, nread, state2) =>
{
bytesRead += nread;
if (nread == 0)
if (nread <= 0)
{
tcp2.Dispose();
}