/// <summary> /// Worker thread that cleans up timed-out connections. /// </summary> static internal void ConnectionPoolWorkerThread() { bool shuttingDown = false; // Console.WriteLine("ConnectionPoolWorkerThread started"); while (true) { bool didWork = false; DateTime now = DateTime.Now; ArrayList pools = null; // Wait on the lock for the pool of pools since // the ConnectionPoolManager.Get might have it and // is declaring its intent to get a slot from one of the pools. lock (poolOfConnectionPools) { pools = new ArrayList(poolOfConnectionPools.Keys); foreach (object obj in pools) { string key = (string)obj; // connection string ConnectionPool pool = (ConnectionPool)poolOfConnectionPools[key]; // if no active slots and no connecting // and no inactive connections and too old if (pool.IsTooOld(now)) { // disconnect old, empty pool from the pool of pools poolOfConnectionPools.Remove(key); } } // Get a snapshot list of pools. Other threads might // be adding more pools to the pool of pools but we // don't care; we'll catch on the next timer iteration. // We are the only thread that removes pools so we // the snapahot will be good for this iteration. pools = new ArrayList(poolOfConnectionPools.Values); // release our lock on the pool of pools } // end lock(poolOfConnectionPools) foreach (object obj in pools) { ConnectionPool pool = (ConnectionPool)obj; // We now have a pool that we can check for inactive // physical connections that we can close physically. while (true) // loop thru the connections in the pool { AdvanConnect advanConnect = null; advanConnect = pool.GetPoolSlotExpired(shuttingDown); if (advanConnect == null) { break; } try { // Console.WriteLine("Closing connection physically"+ // " by ConnectionPoolWorkerThread"); // Close the connection. Do not hold any // locks for the pool of pools or a pool since // the I/O for the close may take a long time. advanConnect.close(); // close the connection } catch {} didWork = true; } } if (didWork) // if we did something then restart the scan { continue; } pools = null; // release the object to garbage collection if (shuttingDown) { // Console.WriteLine("ConnectionPoolWorkerThread returning"); return; } // sleep 10 seconds or until shutdown signaled shuttingDown = shuttingDownEvent.WaitOne(10000, false); // if (shuttingDown) // Console.WriteLine("ConnectionPoolWorkerThread ShuttingDown"); //Thread.Sleep(10000); // sleep 10 seconds } // end while }
/// <summary> /// Find the correct connection pool based on connection string. /// Get an AdvanConnect connection from the pool or create /// the AdvanConnect if none is available. Wait on pool if /// connection limit on pool would be exceeded. /// </summary> /// <param name="connectionString"></param> /// <param name="providerConnection"></param> /// <param name="host"></param> /// <param name="config"></param> /// <param name="trace"></param> /// <param name="timeout"></param> /// <returns></returns> static private AdvanConnect GetConnectionFromPool( string connectionString, IDbConnection providerConnection, String host, IConfig config, ITrace trace, int timeout) { string strValue; AdvanConnect advanConnect; ConnectionPool pool; int minPoolSize = 0; int maxPoolSize = 100; int expirationSeconds = 60; // inactive connection expiration // timespan before removal from pool if (trace == null) { trace = new TraceDV(DrvConst.DRV_TRACE_ID); // "drv" } // if 'Pooling=false' was specified, get a new connection string pooling = config.get(DrvConst.DRV_PROP_CLIENTPOOL); if (pooling != null && (pooling.ToLower(CultureInfo.InvariantCulture) == "false" || pooling.ToLower(CultureInfo.InvariantCulture) == "no")) { advanConnect = new AdvanConnect( providerConnection, host, config, trace, timeout); // leave advanConnect.CanBePooled == false so that // it does not go back into the pool and is physically closed later. return(advanConnect); } // Min Pool Size strValue = config.get(DrvConst.DRV_PROP_MINPOOLSIZE); if (strValue != null) { try { minPoolSize = Int32.Parse(strValue); } catch {} } // Max Pool Size strValue = config.get(DrvConst.DRV_PROP_MAXPOOLSIZE); if (strValue != null) { try { maxPoolSize = Int32.Parse(strValue); } catch {} } while (true) // retry loop to get a pooled connection { // Get a pooled connection. // Wait on the lock for the pool of pools since // the ConnectionPoolWorkerThread might have it and // is busy cleaning up inactive pools. // This lock controls update of this list. Do not // hold the lock for long (i.e. no DB access). lock (poolOfConnectionPools) // lock pool of pools and possibly wait { // if first time, start the worker thread that cleans up connections if (connectionPoolWorkerThread == null) { // create thread and fill in connectionPoolWorkerThread CreateConnectionPoolWorkerThread(); // listen for AppDomain.DomainUnload event so we can // tell the ConnectionPoolWorkerThread to gracefully // shut down inactive connections in the pools. ListenForAppDomainUnload(); } // get a pooled connection for given connection string pool = (ConnectionPool)poolOfConnectionPools[connectionString]; // if no pool for given connection string, build one if (pool == null) { pool = new ConnectionPool( providerConnection.ConnectionTimeout, minPoolSize, maxPoolSize, expirationSeconds); poolOfConnectionPools[connectionString] = pool; // insert } // end if (pool == null) pool.PrepareToGetPoolSlot(); // mark pool for "connect-in-progress" } // end lock(poolOfConnectionPools) // Wait for and lock up a slot in the connection pool // and release the "connect-in-progress" indicator in the pool. // The pool.ConnectingCount will be > 0 and will prevent // the pool from being released while we wait for a slot. // We hold no locks on pool of pools nor individual pool while we wait. advanConnect = pool.GetPoolSlot(providerConnection); // if a physical connection was found in the pool then we're all done! if (advanConnect != null) { if (advanConnect.msg.QuerySocketHealth() == true) // if still alive { return(advanConnect); } advanConnect.close(); // close the bad connection continue; // retry to get a pooled connection } else { break; // no more available connections in pool } } // retry loop to get a pooled connection // we own a slot in the pool // but we need to build a brand new connection try { // connect to the server advanConnect = new AdvanConnect( providerConnection, host, config, trace, timeout); // at this point, we have a good connection advanConnect.connectionPool = pool; advanConnect.CanBePooled = true; // we can pool good ones } catch (Exception) { pool.PutPoolSlot(); // release our slot back into the pool throw; } return(advanConnect); }