e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
179 lines
6.1 KiB
C#
179 lines
6.1 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="ResourcePool.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
namespace System.Web.Util {
|
|
using System.Collections;
|
|
using System.Threading;
|
|
|
|
/*
|
|
* ResourcePool provides a place to store expensive resources,
|
|
* such as network connections, that you want to dispose of when
|
|
* they are underused. A resource pool can be configured to timeout
|
|
* resources at a given interval, and to have a max limit of resources.
|
|
*/
|
|
class ResourcePool : IDisposable {
|
|
ArrayList _resources; // the resources
|
|
int _iDisposable; // resources below this index are candidates for disposal
|
|
int _max; // max number of resources
|
|
Timer _timer; // periodic timer
|
|
TimerCallback _callback; // callback delegate
|
|
TimeSpan _interval; // callback interval
|
|
bool _disposed;
|
|
|
|
internal ResourcePool(TimeSpan interval, int max) {
|
|
_interval = interval;
|
|
_resources = new ArrayList(4);
|
|
_max = max;
|
|
_callback = new TimerCallback(this.TimerProc);
|
|
|
|
Debug.Validate("ResourcePool", this);
|
|
}
|
|
|
|
public void Dispose() {
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing) {
|
|
if (disposing) {
|
|
lock (this) {
|
|
if (!_disposed) {
|
|
if (_resources != null) {
|
|
foreach (IDisposable resource in _resources) {
|
|
resource.Dispose();
|
|
}
|
|
|
|
_resources.Clear();
|
|
}
|
|
|
|
if (_timer != null) {
|
|
_timer.Dispose();
|
|
}
|
|
|
|
Debug.Trace("ResourcePool", "Disposed");
|
|
_disposed = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal object RetrieveResource() {
|
|
object result = null;
|
|
|
|
// avoid lock in common case
|
|
if (_resources.Count != 0) {
|
|
lock (this) {
|
|
Debug.Validate("ResourcePool", this);
|
|
|
|
if (!_disposed) {
|
|
if (_resources.Count == 0) {
|
|
result = null;
|
|
Debug.Trace("ResourcePool", "RetrieveResource returned null");
|
|
} else {
|
|
result = _resources[_resources.Count-1];
|
|
_resources.RemoveAt(_resources.Count-1);
|
|
if (_resources.Count < _iDisposable) {
|
|
_iDisposable = _resources.Count;
|
|
}
|
|
}
|
|
|
|
Debug.Validate("ResourcePool", this);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal void StoreResource(IDisposable o) {
|
|
|
|
lock (this) {
|
|
Debug.Validate("ResourcePool", this);
|
|
|
|
if (!_disposed) {
|
|
if (_resources.Count < _max) {
|
|
_resources.Add(o);
|
|
o = null;
|
|
if (_timer == null) {
|
|
|
|
#if DBG
|
|
if (!Debug.IsTagPresent("Timer") || Debug.IsTagEnabled("Timer"))
|
|
#endif
|
|
{
|
|
_timer = new Timer(_callback, null, _interval, _interval);
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug.Validate("ResourcePool", this);
|
|
}
|
|
}
|
|
|
|
if (o != null) {
|
|
Debug.Trace("ResourcePool", "StoreResource reached max=" + _max);
|
|
o.Dispose();
|
|
}
|
|
}
|
|
|
|
void TimerProc(Object userData) {
|
|
IDisposable[] a = null;
|
|
|
|
lock (this) {
|
|
Debug.Validate("ResourcePool", this);
|
|
|
|
if (!_disposed) {
|
|
if (_resources.Count == 0) {
|
|
if (_timer != null) {
|
|
_timer.Dispose();
|
|
_timer = null;
|
|
}
|
|
|
|
Debug.Validate("ResourcePool", this);
|
|
return;
|
|
}
|
|
|
|
a = new IDisposable[_iDisposable];
|
|
_resources.CopyTo(0, a, 0, _iDisposable);
|
|
_resources.RemoveRange(0, _iDisposable);
|
|
|
|
// It means that whatever remain in _resources will be disposed
|
|
// next time the timer proc is called.
|
|
_iDisposable = _resources.Count;
|
|
|
|
Debug.Trace("ResourcePool", "Timer disposing " + a.Length + "; remaining=" + _resources.Count);
|
|
Debug.Validate("ResourcePool", this);
|
|
}
|
|
}
|
|
|
|
if (a != null) {
|
|
for (int i = 0; i < a.Length; i++) {
|
|
try {
|
|
a[i].Dispose();
|
|
}
|
|
catch {
|
|
// ignore all errors
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
internal void DebugValidate() {
|
|
Debug.CheckValid(_resources != null, "_resources != null");
|
|
|
|
Debug.CheckValid(0 <= _iDisposable && _iDisposable <= _resources.Count,
|
|
"0 <= _iDisposable && _iDisposable <= _resources.Count" +
|
|
";_iDisposable=" + _iDisposable +
|
|
";_resources.Count=" + _resources.Count);
|
|
|
|
Debug.CheckValid(_interval > TimeSpan.Zero, "_interval > TimeSpan.Zero" +
|
|
";_interval=" + _interval);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|