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:
parent
8e818e3549
commit
c809beec18
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue