Return last block from SocketInput when data is fully consumed

- This reduces Kestrel's memory usage for idle connections.
This commit is contained in:
Stephen Halter 2016-08-09 14:49:03 -07:00
parent 375e8b7022
commit 0edf36bd21
1 changed files with 40 additions and 21 deletions

View File

@ -52,6 +52,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
} }
public MemoryPoolBlock IncomingStart() public MemoryPoolBlock IncomingStart()
{
lock (_sync)
{ {
const int minimumSize = 2048; const int minimumSize = 2048;
@ -66,6 +68,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
return _pinned; return _pinned;
} }
}
public void IncomingComplete(int count, Exception error) public void IncomingComplete(int count, Exception error)
{ {
@ -112,6 +115,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
{ {
Debug.Assert(_pinned != null); Debug.Assert(_pinned != null);
lock (_sync)
{
if (_pinned != null) if (_pinned != null)
{ {
if (_pinned != _tail) if (_pinned != _tail)
@ -122,6 +127,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
_pinned = null; _pinned = null;
} }
} }
}
private void Complete() private void Complete()
{ {
@ -172,18 +178,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
} }
returnStart = _head; returnStart = _head;
var consumedAll = !consumed.IsDefault && consumed.IsEnd;
if (consumedAll && _pinned != _tail)
{
// Everything has been consumed and no data is being written to the
// _tail block, so return all blocks between _head and _tail inclusive.
returnEnd = null;
_head = null;
_tail = null;
}
else
{
returnEnd = consumed.Block; returnEnd = consumed.Block;
_head = consumed.Block; _head = consumed.Block;
_head.Start = consumed.Index; _head.Start = consumed.Index;
}
// Must call Subtract() after _head has been advanced, to avoid producer starting too early and growing // Must call Subtract() after _head has been advanced, to avoid producer starting too early and growing
// buffer beyond max length. // buffer beyond max length.
_bufferSizeControl?.Subtract(lengthConsumed); _bufferSizeControl?.Subtract(lengthConsumed);
} }
if (!examined.IsDefault && // If _head is null, everything has been consumed and examined.
examined.IsEnd && var examinedAll = (!examined.IsDefault && examined.IsEnd) || _head == null;
ReadingInput) if (examinedAll && ReadingInput)
{ {
_manualResetEvent.Reset(); _manualResetEvent.Reset();