internal Catalog(AdvanConnect advanConnect) { // associate with the pooled connection this.AdvanConnect = advanConnect; tables = new System.Collections.Hashtable(); }
/* ** Name: Close ** ** History: ** 27-Aug-02 (thoda04) ** Created. */ /// <summary> /// Close the database connection or release it back into connection pool. /// </summary> public override void Close() { if (_state == ConnectionState.Closed) return; if (ActiveDataReader != null) // Close any open DataReader ActiveDataReader.Close(); if (advanConnect != null) { if (Transaction != null && Transaction.HasAlreadyBeenCommittedOrRolledBack == false) { Transaction.Rollback(); Transaction = null; } // put the advantage connection back into pool or close it advanConnect.CloseOrPutBackIntoConnectionPool(); advanConnect = null; } ConnectionState oldState = _state; _state = ConnectionState.Closed; _serverVersion = null; // ServerVersion property is now invalid // Raise the connection state change FireStateChange(oldState, _state); // old, new }
/* ** Name: Open ** ** History: ** 27-Aug-02 (thoda04) ** Created. */ /// <summary> /// Open the database connection and set the ConnectionState property. /// </summary> public override void Open() { System.EnterpriseServices.ITransaction transaction; if (_state == ConnectionState.Open) throw new InvalidOperationException("The connection is already open."); if (config == null) // if no connection string then bad news throw new InvalidOperationException("Host specification missing"); string host = DataSource; if (host == null) throw new InvalidOperationException("Host specification missing"); // if not "servername:port" format then // get the port number from keyword=value NameValueCollection if (host.IndexOf(":") == -1) { string port = config.Get(DrvConst.DRV_PROP_PORT); if (port == null || port.Length == 0) port = "II7"; // no "Port=" then default to "II7" host += ":" + port.ToString(); // add ":portid" to host } advanConnect = AdvanConnectionPoolManager.Get( ConnectionString, this, host, config, null, ConnectionTimeout); // advanConnect internal connection object may be later used by // two threads: the application thread and the MSDTC proxy thread. // The advanConnect usage count will block release of the internal // connection advanConnect object back into the connection pool // until each is finished and calls // advanConnect.CloseOrPutBackIntoConnectionPool() method. // See DTCEnlistment.Enlist() method for MSDTC proxy claim stake. advanConnect.ReferenceCountIncrement(); // application thread stakes it claim ConnectionState oldState = _state; _state = ConnectionState.Open; // Raise the connection state change event FireStateChange(oldState, _state); // old, new string persistSecurityInfo = config.Get(DrvConst.DRV_PROP_PERSISTSEC); if (persistSecurityInfo == null || (ToInvariantLower(persistSecurityInfo) != "true" && ToInvariantLower(persistSecurityInfo) != "yes")) _connectionString = _connectionStringSanitized; transaction = EnlistDistributedTransactionIsNeeded(); if (transaction != null) EnlistDistributedTransaction(transaction, false); // implicit enlistment }
/// <summary> /// Release a connection slot, and possibly /// a good AdvanConnect object back into the pool. /// </summary> /// <param name="advanConnect"></param> internal void PutPoolSlot(AdvanConnect advanConnect) { lock (this) // lock the pool as we update the list { ActiveCount--; // count of active connection slots if (ActiveCount < MaxCount) { waitingOnPoolSize.Set(); // pool is signaled available } if (advanConnect == null) // if just releasing our slot { return; } DateTime expire; if (ConnectExpirationTimeSpan == TimeSpan.MaxValue) { expire = DateTime.MaxValue; // never expire the connection } else { try { // Expire inactive phys connection after specified interval. // If connection comes off the available list, is used, // and is put back on the available list then // this code here will be called again to push // the expiration time into the future. expire = DateTime.Now + ConnectExpirationTimeSpan; } catch (ArgumentOutOfRangeException) // catch any overflow { expire = DateTime.MaxValue; // never expire the connection } } advanConnect.expirationDate = expire; // inactive connection expiration time advanConnect.Connection = null; // release the IngresConnection obj advanConnect.connectionPool = null; AvailableList.Add(advanConnect); // add connection back into avail } // end lock(this) } // end PutPoolSlot
} // end GetPoolSlot /// <summary> /// Get the oldest expired AdvanConnect connection from the pool. /// </summary> /// <param name="shuttingDown">If true then return all in avail list. /// Otherwise, just return the "too old" connections.</param> /// <returns></returns> internal AdvanConnect GetPoolSlotExpired(bool shuttingDown) { lock (this) { // if no inactive physical connections then return if (AvailableList.Count == 0) { return(null); } // if physical connections at or below min then return if (ActiveCount + AvailableList.Count <= MinCount && !shuttingDown) { return(null); } DateTime now = DateTime.Now; AdvanConnect advanConnect = // get first (and oldest in list) (AdvanConnect)AvailableList[0]; if (advanConnect.expirationDate > now && // if still good !shuttingDown) { return(null); } // remove the old, expired connection from the pool AvailableList.RemoveAt(0); advanConnect.connectionPool = null; // if no one is using the pool, start the death knell on it if (ActiveCount == 0 && AvailableList.Count == 0 && ConnectingCount == 0) { PoolExpirationDate = now + TimeSpan.FromTicks( 60 * TimeSpan.TicksPerSecond); // gone in 60 seconds } return(advanConnect); // return the oldest, expired AdvanConnect } // end lock(pool) } // end GetPoolSlotExpired()
/// <summary> /// Put the AdvanConnect connection back into the connection pool /// to make it available to others. /// </summary> /// <param name="advanConnect"></param> static internal void Put(AdvanConnect advanConnect) { if (advanConnect == null) // safety check { return; } ConnectionPool pool = advanConnect.connectionPool; if (advanConnect.msg != null && advanConnect.msg.isSocketConnected() == false) { // underlying connection socket to msg is damaged advanConnect.CanBePooled = false; } // if cannot be pooled if (advanConnect.CanBePooled == false || pool == null) { // Null out connectionPool reference to avoid the close() // method trying to remove the connection pool slot. // We will do it ourselves. advanConnect.connectionPool = null; // Console.WriteLine("Closing connection physically by Put"); advanConnect.close(); // close the internal connection // if connection was in the pool in the past but is now damaged if (pool != null) { pool.PutPoolSlot(null); // release the pool slot } } else { pool.PutPoolSlot(advanConnect); // put good conn back into pool } return; }
/// <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); }
public UserSearchOrder(AdvanConnect advanConnect) { AdvanConnect = advanConnect; bool isGateway = false; string Username = null; string DBAname = null; string SystemOwnername = "$ingres"; if (!advanConnect.conn.is_ingres) { string str; if ((str = AdvanConnect.conn.dbCaps.getDbCap("DBMS_TYPE")) != null) { str = str.ToUpper( System.Globalization.CultureInfo.InvariantCulture); // certain gateways don't have iidbconstants(system_owner) if (str.Equals("VSAM") || str.Equals("IMS")) { isGateway = true; } } } IDbCommand cmd = AdvanConnect.Connection.CreateCommand(); if (isGateway) { cmd.CommandText = "SELECT user_name, dba_name, dba_name FROM iidbconstants"; } else // Ingres and other full-service gateways { cmd.CommandText = "SELECT user_name, dba_name, system_owner FROM iidbconstants"; } // send the query to the database catalog to get columns IDataReader rdr = null; try { // read the user search order rdr = cmd.ExecuteReader(); while (rdr.Read()) // dummy loop for break convenience { if (!rdr.IsDBNull(0)) { Username = rdr.GetString(0).TrimEnd(); } if (!rdr.IsDBNull(1)) { DBAname = rdr.GetString(1).TrimEnd(); } if (!rdr.IsDBNull(2)) { SystemOwnername = rdr.GetString(2).TrimEnd(); } break; // read just the first row } // end dummy while loop } catch (SqlEx /*ex*/) { //Console.WriteLine(ex); throw; } finally { if (rdr != null) { cmd.Cancel(); // cancel the remainder to avoid spurious msg rdr.Close(); // close the data reader } } // eliminate duplicates if (Username != null) { if (DBAname != null) { if (DBAname.Equals(Username)) { DBAname = null; } } if (SystemOwnername != null) { if (SystemOwnername.Equals(Username)) { SystemOwnername = null; } } } if (DBAname != null) { if (SystemOwnername != null) { if (SystemOwnername.Equals(DBAname)) { SystemOwnername = null; } } } if (Username != null) { base.Add(Username); } if (DBAname != null) { base.Add(DBAname); } if (SystemOwnername != null) { base.Add(SystemOwnername); } }