Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

MemoryPool2 Stack->Queue, Allocate returns newest #310

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 26 additions & 17 deletions src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPool2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public class MemoryPool2 : IDisposable
/// Thread-safe collection of blocks which are currently in the pool. A slab will pre-allocate all of the block tracking objects
/// and add them to this collection. When memory is requested it is taken from here first, and when it is returned it is re-added.
/// </summary>
private readonly ConcurrentStack<MemoryPoolBlock2> _blocks = new ConcurrentStack<MemoryPoolBlock2>();
private readonly ConcurrentQueue<MemoryPoolBlock2> _blocks = new ConcurrentQueue<MemoryPoolBlock2>();

/// <summary>
/// Thread-safe collection of slabs which have been allocated by this pool. As long as a slab is in this collection and slab.IsActive,
/// the blocks will be added to _blocks when returned.
/// </summary>
private readonly ConcurrentStack<MemoryPoolSlab2> _slabs = new ConcurrentStack<MemoryPoolSlab2>();
private readonly ConcurrentQueue<MemoryPoolSlab2> _slabs = new ConcurrentQueue<MemoryPoolSlab2>();

/// <summary>
/// This is part of implementing the IDisposable pattern.
Expand Down Expand Up @@ -74,33 +74,33 @@ public MemoryPoolBlock2 Lease(int minimumSize)
slab: null);
}

while (true)
MemoryPoolBlock2 block;
if (_blocks.TryDequeue(out block))
{
MemoryPoolBlock2 block;
if (_blocks.TryPop(out block))
{
// block successfully taken from the stack - return it
return block;
}
// no blocks available - grow the pool and try again
AllocateSlab();
// block successfully taken from the stack - return it
return block;
}
// no blocks available - grow the pool
return AllocateSlab();
}

/// <summary>
/// Internal method called when a block is requested and the pool is empty. It allocates one additional slab, creates all of the
/// block tracking objects, and adds them all to the pool.
/// </summary>
private void AllocateSlab()
private MemoryPoolBlock2 AllocateSlab()
{
var slab = MemoryPoolSlab2.Create(_slabLength);
_slabs.Push(slab);
_slabs.Enqueue(slab);

var basePtr = slab.ArrayPtr;
var firstOffset = (int)((_blockStride - 1) - ((ulong)(basePtr + _blockStride - 1) % _blockStride));

for (var offset = firstOffset;
offset + _blockLength <= _slabLength;
var poolAllocationLength = _slabLength - (_blockLength + _blockStride);

var offset = firstOffset;
for (;
offset < poolAllocationLength;
offset += _blockStride)
{
var block = MemoryPoolBlock2.Create(
Expand All @@ -110,6 +110,15 @@ private void AllocateSlab()
slab);
Return(block);
}

// return last block rather than adding to pool
var newBlock = MemoryPoolBlock2.Create(
new ArraySegment<byte>(slab.Array, offset, _blockLength),
basePtr,
this,
slab);

return newBlock;
}

/// <summary>
Expand All @@ -123,7 +132,7 @@ private void AllocateSlab()
public void Return(MemoryPoolBlock2 block)
{
block.Reset();
_blocks.Push(block);
_blocks.Enqueue(block);
}

protected virtual void Dispose(bool disposing)
Expand All @@ -133,7 +142,7 @@ protected virtual void Dispose(bool disposing)
if (disposing)
{
MemoryPoolSlab2 slab;
while (_slabs.TryPop(out slab))
while (_slabs.TryDequeue(out slab))
{
// dispose managed state (managed objects).
slab.Dispose();
Expand Down