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

@ -53,18 +53,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
public MemoryPoolBlock IncomingStart() public MemoryPoolBlock IncomingStart()
{ {
const int minimumSize = 2048; lock (_sync)
if (_tail != null && minimumSize <= _tail.Data.Offset + _tail.Data.Count - _tail.End)
{ {
_pinned = _tail; const int minimumSize = 2048;
}
else
{
_pinned = _memory.Lease();
}
return _pinned; if (_tail != null && minimumSize <= _tail.Data.Offset + _tail.Data.Count - _tail.End)
{
_pinned = _tail;
}
else
{
_pinned = _memory.Lease();
}
return _pinned;
}
} }
public void IncomingComplete(int count, Exception error) public void IncomingComplete(int count, Exception error)
@ -112,14 +115,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
{ {
Debug.Assert(_pinned != null); Debug.Assert(_pinned != null);
if (_pinned != null) lock (_sync)
{ {
if (_pinned != _tail) if (_pinned != null)
{ {
_memory.Return(_pinned); if (_pinned != _tail)
} {
_memory.Return(_pinned);
}
_pinned = null; _pinned = null;
}
} }
} }
@ -172,18 +178,31 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Http
} }
returnStart = _head; returnStart = _head;
returnEnd = consumed.Block;
_head = consumed.Block; var consumedAll = !consumed.IsDefault && consumed.IsEnd;
_head.Start = consumed.Index; 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;
_head = consumed.Block;
_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();