Return last block from SocketInput when data is fully consumed
- This reduces Kestrel's memory usage for idle connections.
This commit is contained in:
parent
375e8b7022
commit
0edf36bd21
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue