// // Pool Insert/Delete methods // public void PutNewConnection(SqlInternalConnection con) { con.InPool = true; // mark as back in pool _stackNew.Push(con); _poolCounter.Modify(cAddFree); SafeNativeMethods.ReleaseSemaphore(_waitHandles[SEMAPHORE_HANDLE].Handle, 1, 0); }
internal void InitPool() { try { if (this.minItems > 0) { for (int i = 0; i < this.minItems; i++) { try { _freeItems.Push(CreateSocket()); } catch (Exception ex) { _logger.LogError(ex, $"Failed to put {nameof(PooledSocket)} {i} in Pool"); } // cannot connect to the server if (!this.isAlive) { break; } } } if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Pool has been inited for {0} with {1} sockets", _endPoint, this.minItems); } } catch (Exception e) { _logger.LogError("Could not init pool.", new EventId(0), e); this.MarkAsDead(); } }
// Called when the cleanup-timer ticks over. private void CleanupCallback(Object state) { // This is the automatic prunning method. Every period, we will perform a two-step // process. First, for the connections above MinPool, we will obtain the semaphore for // the connection 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 // connection, or until we have exhausted all the connections on the old stack. After // that, push all connections on the new stack to the old stack. So, every period // the connections on the old stack are destroyed and the connections on the new stack // are pushed to the old stack. All connections that are currently out and in use are // not on either stack. With this logic, a connection is prunned if unused for at least // one period but not more than two periods. // Destroy free connections above MinPool size from old stack. while (_poolCounter.TotalCount > _ctrl.MinPool) { // While above MinPoolSize... if (_waitHandles[SEMAPHORE_HANDLE].WaitOne(0, false) /* != WAIT_TIMEOUT */) { // We obtained a connection from the semaphore. SqlInternalConnection con = (SqlInternalConnection)_stackOld.Pop(); if (con != null) { // If we obtained one from the old stack, destroy it. _poolCounter.Modify(-cAddFree); DestroyConnection(con); } else { // Else we exhausted the old stack, so break. SafeNativeMethods.ReleaseSemaphore(_waitHandles[SEMAPHORE_HANDLE].Handle, 1, 0); break; } } else { break; } } // Push to the old-stack. For each free connection, move connection from new stack // to old stack. if (_waitHandles[SEMAPHORE_HANDLE].WaitOne(0, false) /* != WAIT_TIMEOUT */) { for (;;) { SqlInternalConnection con = (SqlInternalConnection)_stackNew.Pop(); if (con == null) { break; } _stackOld.Push(con); } SafeNativeMethods.ReleaseSemaphore(_waitHandles[SEMAPHORE_HANDLE].Handle, 1, 0); } // Make sure we're at quota by posting a callback to the threadpool. ThreadPool.QueueUserWorkItem(new WaitCallback(PoolCreateRequest)); }