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 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 readonly Func<UvStreamHandle, int, object, Libuv.uv_buf_t> _allocCallback = AllocCallback;
private static long _lastConnectionId; private static long _lastConnectionId;
@ -113,28 +113,34 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
result.Data.Count); 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 normalRead = status > 0;
var normalDone = readCount == 0 && (errorCode == 0 || errorCode == Constants.ECONNRESET || errorCode == Constants.EOF); var normalDone = status == 0 || status == Constants.ECONNRESET || status == Constants.EOF;
var errorDone = !(normalDone || normalRead); var errorDone = !(normalDone || normalRead);
var readCount = normalRead ? status : 0;
if (normalRead) if (normalRead)
{ {
Log.ConnectionRead(_connectionId, readCount); Log.ConnectionRead(_connectionId, readCount);
} }
else if (normalDone || errorDone) else
{ {
_socket.ReadStop(); _socket.ReadStop();
Log.ConnectionReadFin(_connectionId); 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() void IConnectionControl.Pause()

View File

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

View File

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

View File

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

View File

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

View File

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