LifecycledComponentsReleasePolicy
Tracks all components requiring decomission ( RequiresPolicyRelease)
using Castle.Core;
using Castle.Core.Internal;
using Castle.MicroKernel.Internal;
using Castle.Windsor.Diagnostics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
namespace Castle.MicroKernel.Releasers
{
[Serializable]
public class LifecycledComponentsReleasePolicy : IReleasePolicy, IDisposable
{
private readonly Dictionary<object, Burden> instance2Burden = new Dictionary<object, Burden>((IEqualityComparer<object>)ReferenceEqualityComparer<object>.get_Instance());
private readonly Lock lock = Lock.Create();
private readonly ITrackedComponentsPerformanceCounter perfCounter;
private ITrackedComponentsDiagnostic trackedComponentsDiagnostic;
private Burden[] TrackedObjects {
get {
using (ILockHolder lockHolder = lock.ForReading(false)) {
bool lockAcquired = lockHolder.LockAcquired;
return instance2Burden.Values.ToArray();
}
}
}
public LifecycledComponentsReleasePolicy(IKernel kernel)
: this(GetTrackedComponentsDiagnostic(kernel), null)
{
}
public LifecycledComponentsReleasePolicy(ITrackedComponentsDiagnostic trackedComponentsDiagnostic, ITrackedComponentsPerformanceCounter trackedComponentsPerformanceCounter)
{
this.trackedComponentsDiagnostic = trackedComponentsDiagnostic;
perfCounter = (trackedComponentsPerformanceCounter ?? NullPerformanceCounter.Instance);
if (trackedComponentsDiagnostic != null)
trackedComponentsDiagnostic.TrackedInstancesRequested += trackedComponentsDiagnostic_TrackedInstancesRequested;
}
private LifecycledComponentsReleasePolicy(LifecycledComponentsReleasePolicy parent)
: this(parent.trackedComponentsDiagnostic, parent.perfCounter)
{
}
public void Dispose()
{
KeyValuePair<object, Burden>[] source = default(KeyValuePair<object, Burden>[]);
using (lock.ForWriting()) {
if (trackedComponentsDiagnostic != null) {
trackedComponentsDiagnostic.TrackedInstancesRequested -= trackedComponentsDiagnostic_TrackedInstancesRequested;
trackedComponentsDiagnostic = null;
}
source = instance2Burden.ToArray();
instance2Burden.Clear();
}
foreach (KeyValuePair<object, Burden> item in source.Reverse()) {
item.Value.Released -= OnInstanceReleased;
perfCounter.DecrementTrackedInstancesCount();
item.Value.Release();
}
}
public IReleasePolicy CreateSubPolicy()
{
return new LifecycledComponentsReleasePolicy(this);
}
public bool HasTrack(object instance)
{
if (instance == null)
return false;
using (lock.ForReading())
return instance2Burden.ContainsKey(instance);
}
public void Release(object instance)
{
if (instance != null) {
Burden value;
using (lock.ForWriting()) {
if (!instance2Burden.TryGetValue(instance, out value))
return;
}
value.Release();
}
}
public virtual void Track(object instance, Burden burden)
{
if (!burden.RequiresPolicyRelease) {
object arg = burden.Model.CustomLifestyle ?? ((object)burden.Model.LifestyleType);
throw new ArgumentException($"""{instance}""{arg}""");
}
try {
using (lock.ForWriting())
instance2Burden.Add(instance, burden);
} catch (ArgumentNullException) {
throw;
} catch (ArgumentException) {
throw HelpfulExceptionsUtil.TrackInstanceCalledMultipleTimes(instance, burden);
}
burden.Released += OnInstanceReleased;
perfCounter.IncrementTrackedInstancesCount();
}
private void OnInstanceReleased(Burden burden)
{
using (lock.ForWriting()) {
if (!instance2Burden.Remove(burden.Instance))
return;
}
burden.Released -= OnInstanceReleased;
perfCounter.DecrementTrackedInstancesCount();
}
private void trackedComponentsDiagnostic_TrackedInstancesRequested(object sender, TrackedInstancesEventArgs e)
{
e.AddRange(TrackedObjects);
}
public static ITrackedComponentsDiagnostic GetTrackedComponentsDiagnostic(IKernel kernel)
{
return ((IDiagnosticsHost)kernel.GetSubSystem(SubSystemConstants.DiagnosticsKey))?.GetDiagnostic<ITrackedComponentsDiagnostic>();
}
[SecuritySafeCritical]
public static ITrackedComponentsPerformanceCounter GetTrackedComponentsPerformanceCounter(IPerformanceMetricsFactory perfMetricsFactory)
{
return NullPerformanceCounter.Instance;
}
}
}