/// <devdoc> /// <para>Places a new/reusable stream in the new stack of the pool</para> /// </devdoc> private void PutNew(PooledStream pooledStream) { GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#" + ValidationHelper.HashString(pooledStream)); GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?"); GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool."); m_StackNew.Push(pooledStream); Semaphore.ReleaseSemaphore(); GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew"); }
/// <devdoc> /// <para>Places a new/reusable stream in the new stack of the pool</para> /// </devdoc> private void PutNew(PooledStream pooledStream) { GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#" + ValidationHelper.HashString(pooledStream)); GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?"); GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool."); m_StackNew.Push(pooledStream); // ensure that the semaphore's count is incremented to signal an available connection is in // the pool Semaphore.ReleaseSemaphore(); GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew"); }
/// <summary> /// <para>This is called by a timer, to check for needed cleanup of idle pooled streams</para> /// </summary> private void CleanupCallback() { // Called when the cleanup-timer ticks over. // // This is the automatic prunning method. Every period, we will perform a two-step // process. First, for the objects above MinPool, we will obtain the semaphore for // the object and then destroy it if it was on the old stack. We will continue this // until we either reach MinPool size, or we are unable to obtain a free object, or // until we have exhausted all the objects on the old stack. After that, push all // objects on the new stack to the old stack. So, every period the objects on the // old stack are destroyed and the objects on the new stack are pushed to the old // stack. All objects that are currently out and in use are not on either stack. // With this logic, a object is prunned if unused for at least one period but not // more than two periods. // Destroy free objects above MinPool size from old stack. while (Count > MinPoolSize) // While above MinPoolSize... { if (Semaphore.WaitOne(0, false)) // != WaitTimeout // We obtained a objects from the semaphore. { PooledStream pooledStream = (PooledStream)m_StackOld.Pop(); if (null != pooledStream) { // If we obtained one from the old stack, destroy it. Destroy(pooledStream); } else { // Else we exhausted the old stack, so break. Semaphore.ReleaseSemaphore(); break; } } else { break; } } // Push to the old-stack. For each free object, move object from new stack // to old stack. if (Semaphore.WaitOne(0, false)) // != WaitTimeout { for (;;) { PooledStream pooledStream = (PooledStream)m_StackNew.Pop(); if (null == pooledStream) { break; } GlobalLog.Assert(!pooledStream.IsEmancipated, "Pooled object not in pool."); GlobalLog.Assert(pooledStream.CanBePooled, "Pooled object is not poolable."); m_StackOld.Push(pooledStream); } Semaphore.ReleaseSemaphore(); } }
/// <summary> /// <para>This is called by a timer, to check for needed cleanup of idle pooled streams</para> /// </summary> private void CleanupCallback() { // Called when the cleanup-timer ticks over. // // This is the automatic prunning method. Every period, we will perform a two-step // process. First, for the objects above MinPool, we will obtain the semaphore for // the object and then destroy it if it was on the old stack. We will continue this // until we either reach MinPool size, or we are unable to obtain a free object, or // until we have exhausted all the objects on the old stack. After that, push all // objects on the new stack to the old stack. So, every period the objects on the // old stack are destroyed and the objects on the new stack are pushed to the old // stack. All objects that are currently out and in use are not on either stack. // With this logic, a object is prunned if unused for at least one period but not // more than two periods. // Destroy free objects above MinPool size from old stack. while (Count > MinPoolSize) // While above MinPoolSize... // acquiring the Semaphore gives us a license to remove one and only // one connection from the pool { if (Semaphore.WaitOne(0, false)) // != WaitTimeout // We obtained a objects from the semaphore. { PooledStream pooledStream = (PooledStream)m_StackOld.Pop(); if (null != pooledStream) { // If we obtained one from the old stack, destroy it. Destroy(pooledStream); } else { // Else we exhausted the old stack, so break // and release the Semaphore to indicate that // no connection was actually removed so whatever // we had locked is still available. Semaphore.ReleaseSemaphore(); break; } } else { break; } } // Push to the old-stack. For each free object, move object from new stack // to old stack. The Semaphore guarantees that we are allowed to handle // one connection at a time so moving a connection between stacks is safe since // one connection is reserved for the duration of this loop and we only touch // one connection at a time on the new stack if (Semaphore.WaitOne(0, false)) // != WaitTimeout { for (;;) { PooledStream pooledStream = (PooledStream)m_StackNew.Pop(); if (null == pooledStream) { break; } GlobalLog.Assert(!pooledStream.IsEmancipated, "Pooled object not in pool."); GlobalLog.Assert(pooledStream.CanBePooled, "Pooled object is not poolable."); m_StackOld.Push(pooledStream); } // no connections were actually destroyed so signal that a connection is now // available since we are no longer reserving a connection by holding the // Semaphore Semaphore.ReleaseSemaphore(); } }