Esempio n. 1
0
        /// <summary>
        /// Releases a <paramref name="pooledValue"/> back into the pool.
        /// </summary>
        /// <param name="pooledValue">The pooled value.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public void ReleasePooledValue(Pooled <TValue> pooledValue, CancellationToken cancellationToken = new CancellationToken())
        {
            if (IsDisposed || IsDisposing)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (pooledValue == null)
            {
                throw new ArgumentNullException(nameof(pooledValue));
            }

            if (pooledValue.OwningPool != this)
            {
                throw new ArgumentOutOfRangeException(nameof(pooledValue), "Only pooled values managed by this pool can be released back into the pool.");
            }

            if (pooledValue.HasBeenReleasedBackToPool)
            {
                throw new ArgumentOutOfRangeException(nameof(pooledValue), "Pooled values that have already been released back and returned to the pool cannot be released a second time.");
            }

            if (pooledValue.HasBeenDetachedFromPool)
            {
                throw new ArgumentOutOfRangeException(nameof(pooledValue), "Detached pooled values can no longer be released and returned back into the pool.");
            }

            // else
            cancellationToken.ThrowIfCancellationRequested();

            PooledInstances.Enqueue(pooledValue.Value);
            RaisePropertyChanged(nameof(AvailableInstancesCount));

            pooledValue.HasBeenReleasedBackToPool = true;
        }
Esempio n. 2
0
        /// <summary>
        /// Increases the total size of the pool by the amount specified.
        /// </summary>
        /// <param name="increaseBy">The amount of values to increase the pool by.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task IncreasePoolSizeAsync(int increaseBy = 1, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (IsDisposed || IsDisposing)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (increaseBy < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(increaseBy));
            }

            for (int i = 0; i < increaseBy; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var instance = await Task.Run(() => InstanceBuilder.Invoke(cancellationToken), cancellationToken).ConfigureAwait(false);

                await Task.Run(() =>
                {
                    PooledInstances.Enqueue(instance);
                }, cancellationToken).ConfigureAwait(false);

                Interlocked.Increment(ref _totalInstancesCount);
                RaisePropertyChanged(nameof(TotalInstancesCount));
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (IsDisposing || IsDisposed)
            {
                return;
            }

            try
            {
                IsDisposing = true;
                if (PooledInstances.IsEmpty)
                {
                    return;
                }

                while (PooledInstances.IsEmpty == false)
                {
                    TValue value;
                    while (PooledInstances.TryDequeue(out value) == false)
                    {
                        var valueAsIDisposable = value as IDisposable;
                        valueAsIDisposable?.Dispose();

                        if (PooledInstances.IsEmpty)
                        {
                            break;
                        }
                    }
                }
            }
            finally
            {
                IsDisposed  = true;
                IsDisposing = false;

                PooledInstances = null;
                InstanceBuilder = null;

                GC.SuppressFinalize(this);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Decreases the size of the pool by the amount of instances specified.
        /// This only has an effect if there are any instances currently available to be
        /// acquired, this has no effect on already and currently acquired instances.
        /// </summary>
        /// <param name="decreaseBy">The amount of values to decrease the pool by.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentOutOfRangeException">
        /// Cannot decrease the amount of (available) pooled items by less than 0
        /// or
        /// Cannot decrease the amount of (available) pooled items by more than what's available.
        /// </exception>
        public async Task DecreaseAvailablePoolSizeAsync(int decreaseBy = 1, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (IsDisposed || IsDisposing)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            if (decreaseBy < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(decreaseBy), "Cannot decrease the amount of (available) pooled items by less than 0");
            }

            if (decreaseBy > PooledInstances.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(decreaseBy), "Cannot decrease the amount of (available) pooled items by more than what's available.");
            }

            for (int i = 0; i < decreaseBy; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (PooledInstances.IsEmpty)
                {
                    return; // nothing more to do - the queue is empty
                }
                TValue dequeuedValue;
                while (PooledInstances.IsEmpty == false && PooledInstances.TryDequeue(out dequeuedValue) == false)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    await Task.Yield();
                }

                Interlocked.Decrement(ref _totalInstancesCount);
                RaisePropertyChanged(nameof(TotalInstancesCount));
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Acquires the next available pooled value.
        /// </summary>
        /// <param name="pooledValueAcquisitionMode">The pooled value acquisition mode.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public async Task <Pooled <TValue> > AcquirePooledValueAsync(
            PooledValueAcquisitionMode pooledValueAcquisitionMode = PooledValueAcquisitionMode.AvailableInstanceOrDefaultValue,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (IsDisposed || IsDisposing)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }

            TValue value = default(TValue);

            // check whether we actually currently have any instances left
            if (PooledInstances.IsEmpty)
            {
                if (pooledValueAcquisitionMode == PooledValueAcquisitionMode.AvailableInstanceOrDefaultValue)
                {
                    return(default(Pooled <TValue>));
                }
                else if (pooledValueAcquisitionMode == PooledValueAcquisitionMode.AvailableInstanceOrCreateNewOne)
                {
                    try
                    {
                        value = await Task.Run(() => InstanceBuilder.Invoke(cancellationToken), cancellationToken).ConfigureAwait(false);
                    }
                    catch (TargetInvocationException targetInvocationException)
                    {
                        targetInvocationException.InnerException.ThrowIfNotNull();
                    }
                }
                else
                {
                    while (PooledInstances.IsEmpty || PooledInstances.TryDequeue(out value) == false)
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        await Task.Yield();
                    }
                }
            }
            else
            {
                // try to retrieve the next available / queued value
                if (PooledInstances.TryDequeue(out value) == false)
                {
                    if (pooledValueAcquisitionMode == PooledValueAcquisitionMode.AvailableInstanceOrDefaultValue)
                    {
                        return(default(Pooled <TValue>));
                    }
                    else if (pooledValueAcquisitionMode == PooledValueAcquisitionMode.AvailableInstanceOrCreateNewOne) // build a new one
                    {
                        try
                        {
                            value = await Task.Run(() => InstanceBuilder.Invoke(cancellationToken), cancellationToken).ConfigureAwait(false);
                        }
                        catch (TargetInvocationException targetInvocationException)
                        {
                            targetInvocationException.InnerException.ThrowIfNotNull();
                        }
                    }
                    else
                    {
                        // keep trying
                        while (PooledInstances.TryDequeue(out value) == false)
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            await Task.Yield();
                        }
                    }
                }
            }

            RaisePropertyChanged(nameof(AvailableInstancesCount));
            cancellationToken.ThrowIfCancellationRequested();
            return(new Pooled <TValue>(value, this));
        }