Skip to content
This repository has been archived by the owner on May 21, 2022. It is now read-only.

Commit

Permalink
reworking pooled object events
Browse files Browse the repository at this point in the history
  • Loading branch information
pomma89 committed Apr 7, 2017
1 parent 84dffc8 commit 72aa9fd
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 192 deletions.
4 changes: 0 additions & 4 deletions src/CodeProject.ObjectPool/CodeProject.ObjectPool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,4 @@
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
</ItemGroup>

<ItemGroup>
<Folder Include="Extensibility\" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion src/CodeProject.ObjectPool/Core/ErrorMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace CodeProject.ObjectPool.Core
internal static class ErrorMessages
{
public const string NegativeOrZeroMaximumPoolSize = "Maximum pool size must be greater than zero.";
public const string NullDiagnostics = "Pool diagnostics recorder cannot be null.";
public const string NegativeOrZeroTimeout = "Timeout must be greater than zero.";
public const string NullResource = "Resource cannot be null.";
}
}
124 changes: 66 additions & 58 deletions src/CodeProject.ObjectPool/ObjectPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,55 +37,6 @@ public static class ObjectPool
public class ObjectPool<T> : IObjectPool<T>, IObjectPoolHandle
where T : PooledObject
{
#region Public Properties

/// <summary>
/// Gets the Diagnostics class for the current Object Pool, whose goal is to record data
/// about how the pool operates. By default, however, an object pool records anything; you
/// have to enable it through the <see cref="ObjectPoolDiagnostics.Enabled"/> property.
/// </summary>
public ObjectPoolDiagnostics Diagnostics { get; set; }

/// <summary>
/// Gets the Factory method that will be used for creating new objects.
/// </summary>
public Func<T> FactoryMethod { get; protected set; }

/// <summary>
/// Gets or sets the maximum number of objects that could be available at the same time in
/// the pool.
/// </summary>
public int MaximumPoolSize
{
get
{
return PooledObjects.Capacity;
}
set
{
// Preconditions
Raise.ArgumentOutOfRangeException.If(value < 1, nameof(value), ErrorMessages.NegativeOrZeroMaximumPoolSize);

// Resize the pool and destroy exceeding items, if any.
foreach (var exceedingItem in PooledObjects.Resize(value))
{
DestroyPooledObject(exceedingItem);
}
}
}

/// <summary>
/// Gets the count of the objects currently in the pool.
/// </summary>
public int ObjectsInPoolCount => PooledObjects.Count;

/// <summary>
/// The concurrent buffer containing pooled objects.
/// </summary>
protected PooledObjectBuffer<T> PooledObjects { get; } = new PooledObjectBuffer<T>();

#endregion Public Properties

#region C'tor and Initialization code

/// <summary>
Expand All @@ -99,7 +50,7 @@ public ObjectPool()
/// <summary>
/// Initializes a new pool with specified maximum pool size.
/// </summary>
/// <param name="maximumPoolSize">The maximum pool size limit</param>
/// <param name="maximumPoolSize">The maximum pool size limit.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="maximumPoolSize"/> is less than or equal to zero.
/// </exception>
Expand All @@ -120,18 +71,22 @@ public ObjectPool(Func<T> factoryMethod)
/// <summary>
/// Initializes a new pool with specified factory method and maximum size.
/// </summary>
/// <param name="maximumPoolSize">The maximum pool size limit</param>
/// <param name="maximumPoolSize">The maximum pool size limit.</param>
/// <param name="factoryMethod">The factory method that will be used to create new objects.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// <paramref name="maximumPoolSize"/> is less than or equal to zero.
/// </exception>
public ObjectPool(int maximumPoolSize, Func<T> factoryMethod)
{
// Preconditions
Raise.ArgumentOutOfRangeException.If(maximumPoolSize < 1, nameof(maximumPoolSize), ErrorMessages.NegativeOrZeroMaximumPoolSize);
Raise.ArgumentOutOfRangeException.IfIsLessOrEqual(maximumPoolSize, 0, nameof(maximumPoolSize), ErrorMessages.NegativeOrZeroMaximumPoolSize);

// Assigning properties.
FactoryMethod = factoryMethod;
// Throws an exception if the type does not have default constructor - on purpose! We
// could have added a generic constraint with new (), but we did not want to limit the
// user and force a parameterless constructor.
FactoryMethod = factoryMethod ?? Activator.CreateInstance<T>;

// Max pool size.
MaximumPoolSize = maximumPoolSize;

// Creating a new instance for the Diagnostics class.
Expand All @@ -140,6 +95,55 @@ public ObjectPool(int maximumPoolSize, Func<T> factoryMethod)

#endregion C'tor and Initialization code

#region Public Properties

/// <summary>
/// Gets the Diagnostics class for the current Object Pool, whose goal is to record data
/// about how the pool operates. By default, however, an object pool records anything; you
/// have to enable it through the <see cref="ObjectPoolDiagnostics.Enabled"/> property.
/// </summary>
public ObjectPoolDiagnostics Diagnostics { get; set; }

/// <summary>
/// Gets the Factory method that will be used for creating new objects.
/// </summary>
public Func<T> FactoryMethod { get; protected set; }

/// <summary>
/// Gets or sets the maximum number of objects that could be available at the same time in
/// the pool.
/// </summary>
public int MaximumPoolSize
{
get
{
return PooledObjects.Capacity;
}
set
{
// Preconditions
Raise.ArgumentOutOfRangeException.If(value < 1, nameof(value), ErrorMessages.NegativeOrZeroMaximumPoolSize);

// Resize the pool and destroy exceeding items, if any.
foreach (var exceedingItem in PooledObjects.Resize(value))
{
DestroyPooledObject(exceedingItem);
}
}
}

/// <summary>
/// Gets the count of the objects currently in the pool.
/// </summary>
public int ObjectsInPoolCount => PooledObjects.Count;

/// <summary>
/// The concurrent buffer containing pooled objects.
/// </summary>
protected PooledObjectBuffer<T> PooledObjects { get; } = new PooledObjectBuffer<T>();

#endregion Public Properties

#region Finalizer

/// <summary>
Expand Down Expand Up @@ -263,15 +267,19 @@ protected T CreatePooledObject()
Diagnostics.IncrementObjectsCreatedCount();
}

// Throws an exception if the type does not have default constructor - on purpose! We
// could have added a generic constraint with new (), but we did not want to limit the
// user and force a parameterless constructor.
var newObject = FactoryMethod?.Invoke() ?? Activator.CreateInstance<T>();
if (FactoryMethod == null)
{
// A child class has deleted our factory method. Therefore, we can only return null.
return null;
}

var newObject = FactoryMethod();

// Setting the 'return to pool' action and other properties in the newly created pooled object.
newObject.PooledObjectInfo.Id = Interlocked.Increment(ref _lastPooledObjectId);
newObject.PooledObjectInfo.State = PooledObjectState.Available;
newObject.PooledObjectInfo.Handle = this;

return newObject;
}

Expand Down
4 changes: 2 additions & 2 deletions src/CodeProject.ObjectPool/ParameterizedObjectPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public ParameterizedObjectPool()
/// <summary>
/// Initializes a new pool with specified maximum pool size.
/// </summary>
/// <param name="maximumPoolSize">The maximum pool size limit</param>
/// <param name="maximumPoolSize">The maximum pool size limit.</param>
public ParameterizedObjectPool(int maximumPoolSize)
: this(maximumPoolSize, null)
{
Expand All @@ -118,7 +118,7 @@ public ParameterizedObjectPool(Func<TKey, TValue> factoryMethod)
/// <summary>
/// Initializes a new pool with specified factory method and maximum size.
/// </summary>
/// <param name="maximumPoolSize">The maximum pool size limit</param>
/// <param name="maximumPoolSize">The maximum pool size limit.</param>
/// <param name="factoryMethod">The factory method that will be used to create new objects.</param>
public ParameterizedObjectPool(int maximumPoolSize, Func<TKey, TValue> factoryMethod)
{
Expand Down
76 changes: 39 additions & 37 deletions src/CodeProject.ObjectPool/PooledObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,24 @@ internal bool ReleaseResources()
{
var successFlag = true;

try
{
OnReleaseResources();
}
catch (Exception ex)
if (OnReleaseResources != null)
{
#if !NET35
if (Log.IsWarnEnabled())
try
{
Log.WarnException("[ObjectPool] An unexpected error occurred while releasing resources", ex);
OnReleaseResources();
}
catch (Exception ex)
{
#if !NET35
if (Log.IsWarnEnabled())
{
Log.WarnException("[ObjectPool] An unexpected error occurred while releasing resources", ex);
}
#else
System.Diagnostics.Debug.Assert(ex != null); // Placeholder to avoid warnings
System.Diagnostics.Debug.Assert(ex != null); // Placeholder to avoid warnings
#endif
successFlag = false;
successFlag = false;
}
}

return successFlag;
Expand All @@ -83,57 +86,56 @@ internal bool ResetState()
{
var successFlag = true;

try
if (OnResetState != null)
{
OnResetState();
}
catch (CannotResetStateException crsex)
{
#if !NET35
if (Log.IsDebugEnabled())
try
{
Log.DebugException("[ObjectPool] Object state could not be reset", crsex);
OnResetState();
}
catch (CannotResetStateException crsex)
{
#if !NET35
if (Log.IsDebugEnabled())
{
Log.DebugException("[ObjectPool] Object state could not be reset", crsex);
}
#else
System.Diagnostics.Debug.Assert(crsex != null); // Placeholder to avoid warnings
System.Diagnostics.Debug.Assert(crsex != null); // Placeholder to avoid warnings
#endif
successFlag = false;
}
catch (Exception ex)
{
#if !NET35
if (Log.IsWarnEnabled())
{
Log.WarnException("[ObjectPool] An unexpected error occurred while resetting state", ex);
successFlag = false;
}
catch (Exception ex)
{
#if !NET35
if (Log.IsWarnEnabled())
{
Log.WarnException("[ObjectPool] An unexpected error occurred while resetting state", ex);
}
#else
System.Diagnostics.Debug.Assert(ex != null); // Placeholder to avoid warnings
System.Diagnostics.Debug.Assert(ex != null); // Placeholder to avoid warnings
#endif
successFlag = false;
successFlag = false;
}
}

return successFlag;
}

#endregion Internal Methods - resource and state management

#region Virtual Template Methods - extending resource and state management
#region Events - extending resource and state management

/// <summary>
/// Reset the object state to allow this object to be re-used by other parts of the application.
/// </summary>
protected virtual void OnResetState()
{
}
public Action OnResetState { get; set; }

/// <summary>
/// Releases the object's resources.
/// </summary>
protected virtual void OnReleaseResources()
{
}
public Action OnReleaseResources { get; set; }

#endregion Virtual Template Methods - extending resource and state management
#endregion Events - extending resource and state management

#region Returning object to pool - Dispose and Finalizer

Expand Down
27 changes: 7 additions & 20 deletions src/CodeProject.ObjectPool/PooledObjectWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,37 +31,24 @@ public PooledObjectWrapper(T resource)
Raise.ArgumentNullException.IfIsNull(resource, nameof(resource), ErrorMessages.NullResource);

InternalResource = resource;
}

/// <summary>
/// Triggered by the pool manager when there is no need for this object anymore.
/// </summary>
public Action<T> WrapperReleaseResourcesAction { get; set; }

/// <summary>
/// Triggered by the pool manager just before the object is being returned to the pool.
/// </summary>
public Action<T> WrapperResetStateAction { get; set; }
base.OnReleaseResources += () => OnReleaseResources?.Invoke(InternalResource);
base.OnResetState += () => OnResetState?.Invoke(InternalResource);
}

/// <summary>
/// The resource wrapped inside this class.
/// </summary>
public T InternalResource { get; }

/// <summary>
/// Triggers the <see cref="WrapperReleaseResourcesAction"/>, if any.
/// Triggered by the pool manager when there is no need for this object anymore.
/// </summary>
protected override void OnReleaseResources()
{
WrapperReleaseResourcesAction?.Invoke(InternalResource);
}
public new Action<T> OnReleaseResources { get; set; }

/// <summary>
/// Triggers the <see cref="WrapperResetStateAction"/>, if any.
/// Triggered by the pool manager just before the object is being returned to the pool.
/// </summary>
protected override void OnResetState()
{
WrapperResetStateAction?.Invoke(InternalResource);
}
public new Action<T> OnResetState { get; set; }
}
}
Loading

0 comments on commit 72aa9fd

Please sign in to comment.