131 lines
3.9 KiB
C#
131 lines
3.9 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Buffers;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
|
{
|
|
/// <summary>
|
|
/// A <see cref="IViewBufferScope"/> that uses pooled memory.
|
|
/// </summary>
|
|
public class MemoryPoolViewBufferScope : IViewBufferScope, IDisposable
|
|
{
|
|
public static readonly int MinimumSize = 16;
|
|
private readonly ArrayPool<ViewBufferValue> _viewBufferPool;
|
|
private readonly ArrayPool<char> _charPool;
|
|
private List<ViewBufferValue[]> _available;
|
|
private List<ViewBufferValue[]> _leased;
|
|
private bool _disposed;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of <see cref="MemoryPoolViewBufferScope"/>.
|
|
/// </summary>
|
|
/// <param name="viewBufferPool">
|
|
/// The <see cref="ArrayPool{ViewBufferValue}"/> for creating <see cref="ViewBufferValue"/> instances.
|
|
/// </param>
|
|
/// <param name="charPool">
|
|
/// The <see cref="ArrayPool{Char}"/> for creating <see cref="PagedBufferedTextWriter"/> instances.
|
|
/// </param>
|
|
public MemoryPoolViewBufferScope(ArrayPool<ViewBufferValue> viewBufferPool, ArrayPool<char> charPool)
|
|
{
|
|
_viewBufferPool = viewBufferPool;
|
|
_charPool = charPool;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public ViewBufferValue[] GetPage(int pageSize)
|
|
{
|
|
if (pageSize <= 0)
|
|
{
|
|
throw new ArgumentOutOfRangeException(nameof(pageSize));
|
|
}
|
|
|
|
if (_disposed)
|
|
{
|
|
throw new ObjectDisposedException(typeof(MemoryPoolViewBufferScope).FullName);
|
|
}
|
|
|
|
if (_leased == null)
|
|
{
|
|
_leased = new List<ViewBufferValue[]>(1);
|
|
}
|
|
|
|
ViewBufferValue[] segment = null;
|
|
|
|
// Reuse pages that have been returned before going back to the memory pool.
|
|
if (_available != null && _available.Count > 0)
|
|
{
|
|
segment = _available[_available.Count - 1];
|
|
_available.RemoveAt(_available.Count - 1);
|
|
return segment;
|
|
}
|
|
|
|
try
|
|
{
|
|
segment = _viewBufferPool.Rent(Math.Max(pageSize, MinimumSize));
|
|
_leased.Add(segment);
|
|
}
|
|
catch when (segment != null)
|
|
{
|
|
_viewBufferPool.Return(segment);
|
|
throw;
|
|
}
|
|
|
|
return segment;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void ReturnSegment(ViewBufferValue[] segment)
|
|
{
|
|
if (segment == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(segment));
|
|
}
|
|
|
|
Array.Clear(segment, 0, segment.Length);
|
|
|
|
if (_available == null)
|
|
{
|
|
_available = new List<ViewBufferValue[]>();
|
|
}
|
|
|
|
_available.Add(segment);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public PagedBufferedTextWriter CreateWriter(TextWriter writer)
|
|
{
|
|
if (writer == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(writer));
|
|
}
|
|
|
|
return new PagedBufferedTextWriter(_charPool, writer);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Dispose()
|
|
{
|
|
if (!_disposed)
|
|
{
|
|
_disposed = true;
|
|
|
|
if (_leased == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (var i = 0; i < _leased.Count; i++)
|
|
{
|
|
_viewBufferPool.Return(_leased[i], clearArray: true);
|
|
}
|
|
|
|
_leased.Clear();
|
|
}
|
|
}
|
|
}
|
|
}
|