3 Advanced Features : Using Connection Pooling

Using Connection Pooling
Connection pooling allows you to reuse connections rather than creating a new one every time the data provider needs to establish a connection to the underlying database. The DataDirect Connect for ADO.NET data providers automatically enable connection pooling for your .NET client application.
You can control connection pooling behavior by using connection string options (see the "Connection String Options" section in each data provider’s chapter). For example, you can define the number of connection pools, the number of connections in a pool, and the lifetime of pooled connections.
Connection pooling in ADO.NET is not provided by the .NET Framework. It must be implemented in the ADO.NET data provider itself.
Creating a Connection Pool
Each connection pool is associated with a specific connection string. By default, the connection pool is created when the first connection with a unique connection string connects to the database. The pool is populated with connections up to the minimum pool size. Additional connections can be added until the pool reaches the maximum pool size.
The pool remains active as long as any connections remain open, either in the pool or used by an application with a reference to a Connection object that has an open connection.
If a new connection is opened and the connection string does not exactly match an existing pool, a new pool must be created. By using the same connection string, you can enhance the performance and scalability of your application.
In the following C# code fragment, three new OracleConnection objects are created, but only two connection pools are required to manage them. Note that the first and second connection strings differ by the values assigned for User ID and Password, and by the value of the Min Pool Size option.
DbProviderFactory Factory = DbProviderFactories.GetFactory("DDTek.Oracle");
DbConnection Conn1 = Factory.CreateConnection();
Conn1.ConnectionString =
   "Host=Accounting;Port=1521;User ID=scott;Password=tiger; " +
   "Service Name=ORCL;Min Pool Size=50";
 
Conn1.Open();
// Pool A is created and filled with connections to the minimum pool size
 
DbConnection Conn2 = Factory.CreateConnection();
Conn2.ConnectionString =
   "Host=Accounting;Port=1521;User ID=Jack;Password=quake; " +
   "Service Name=ORCL;Min Pool Size=100";
 
Conn2.Open();
// Pool B is created because the connections strings differ
 
DbConnection Conn3 = Factory.CreateConnection();
Conn3.ConnectionString =
   "Host=Accounting;Port=1521;User ID=scott;Password=tiger; " +
   "Service Name=ORCL;Min Pool Size=50";
 
Conn3.Open();
// Conn3 is assigned an existing connection that was created in Pool A
// when the pool was created for Conn1
Adding Connections to a Pool
A connection pool is created in the process of creating each unique connection string that an application uses. When a pool is created, it is populated with enough connections to satisfy the minimum pool size requirement, set by the Min Pool Size connection string option. If an application is using more connections than Min Pool Size, the data provider allocates additional connections to the pool up to the value of the Max Pool Size connection string option, which sets the maximum number of connections in the pool.
When a Connection object is requested by the application calling the Connection.Open(…) method, the connection is obtained from the pool, if a usable connection is available. A usable connection is defined as a connection that is not currently in use by another valid Connection object, has a matching distributed transaction context (if applicable), and has a valid link to the server.
If the maximum pool size has been reached and no usable connection is available, the request is queued in the data provider. The data provider waits for the value of the Connection Timeout connection string option for a usable connection to return to the application. If this time period expires and no connection has become available, then the data provider returns an error to the application.
You can allow the data provider to create more connections than the specified maximum pool size without affecting the number of connections pooled. This can be useful, for example, to handle occasional spikes in connection requests. By setting the Max Pool Size Behavior connection string option to SoftCap, the number of connections created can exceed the value set for Max Pool Size, but the number of connections pooled does not. When the maximum connections for the pool are in use and a connection request is received, the data provider creates a new connection. When a connection is returned to a pool that is full and contains idle connections, the pooling mechanism selects a connection to be discarded so the connection pool never exceeds the Max Pool Size value. If set to HardCap, when the maximum number of connections allowed in the pool are in use, any new connection requests wait for an available connection until the Connection Timeout is reached.
IMPORTANT: Closing the connection using the Close() or Dispose() method of the Connection object adds or returns the connection to the pool. When the application uses the Close() method, the connection string settings remain as they were before the Open() method was called. If you use the Dispose method to close the connection, the connection string settings are cleared, and the default settings are restored.
Removing Connections from a Pool
A connection is removed from a connection pool when it either exceeds its lifetime as determined by the Load Balance Timeout connection string option, or when a new connection that has a matching connection string is initiated by the application (Connection.Open() is called).
Before returning a connection from the connection pool to an application, the Pool Manager checks to see if the connection has been closed at the server. If the connection is no longer valid, the Pool Manager discards it and returns another connection from the pool, if one is available and valid.
NOTE: By default, if discarding an invalid connection causes the number of connections to drop below the number specified in the Min Pool Size option, a new connection is not created until an application needs one.
You can control the order in which a connection is removed from the connection pool for reuse, based on how frequently or how recently the connection has been used, with the Connection Pool Behavior connection string option. For a balanced use of connections, use the LeastFrequentlyUsed or LeastRecentlyUsed values. Alternatively, for applications that perform better when they use the same connection every time, you can use the MostFrequentlyUsed or MostRecentlyUsed values.
The ClearPool and ClearAllPools methods of the Connection object remove all connections from a connection pool. ClearPool empties the connection pool associated with a specific connection. In contrast, ClearAllPools empties all of the connection pools the data provider uses. Connections that are in use when the method is called are discarded when they are closed.
Handling Dead Connections in a Pool
What happens when an idle connection loses its physical connection to the database? For example, suppose the database server is rebooted or the network experiences a temporary interruption. An application that attempts to connect using an existing Connection object from a pool could receive errors because the physical connection to the database has been lost.
DataDirect Connect for ADO.NET data providers handle this situation transparently to the user. The application does not receive any errors on the Connection.Open() attempt because the data provider simply returns a connection from a connection pool. The first time the Connection object is used to execute a SQL statement (for example, through the Execute method on the Command object), the data provider detects that the physical connection to the server has been lost and attempts to reconnect to the server before executing the SQL statement. If the data provider can reconnect to the server, the result of the SQL execution is returned to the application; no errors are returned to the application. The data provider uses the connection failover options, if enabled, when attempting this seamless reconnection. See “Using Connection Failover” for information about configuring the data provider to connect to a backup server when the primary server is not available.
NOTE: Because the data provider can attempt to reconnect to the database server when executing SQL statements, connection errors can be returned to the application when a statement is executed. If the data provider cannot reconnect to the server (for example, because the server is still down), the execution method throws an error indicating that the reconnect attempt failed, along with specifics about the reason the connection failed.
DataDirect's technique for handling dead connections in connection pools allows for the maximum performance out of the connection pooling mechanism. Some data providers periodically ping the server with a dummy SQL statement while the connections sit idle. Other data providers ping the server when the application requests the use of the connection from the connection pool. Both of these approaches add round trips to the database server and ultimately slow down the application during normal operation of the application is occurring.
Using Reauthentication
By default, the DataDirect Connect for ADO.NET data providers use a connection pool at all times. Each connection pool is defined by a unique connection string; changing the user in the connection string automatically creates a new connection pool. In an environment that uses OS authentication, users might all use the same connection string. However, they must have separate connection pools because their credentials are different.
Typically, you can configure a connection pool to provide scalability for connections. In addition, to help minimize the number of connections required in a connection pool, you can switch the user associated with a connection to another user, a process known as reauthentication. For example, suppose you are using Kerberos authentication to authenticate users using their operating system user name and password.
To reduce the number of connections that must be created and managed, you may want to switch the user associated with a connection to multiple users using reauthentication. For example, suppose your connection pool contains a connection, Conn, which was established using the user ALLUSERS. You can have that connection service multiple users, User A, B, C, and so on, by switching the user associated with the connection Conn to User A, B, C, and so on.
Not all databases support reauthentication. For those databases that do, the user performing the switch must have been granted specific database permissions. Table 3-1 shows DataDirect Connect for ADO.NET support for reauthentication and lists the required database permissions. Refer to your database documentation for information about granting permissions.
 
Oracle 9i and higher1

1
Oracle refers to reauthentication as proxy authentication.

2
Microsoft SQL Server refers to reauthentication as impersonation.

To perform reauthentication on a connection explicitly, call the CurrentUser() property in the data provider’s Connection class. For example, the following code snippet switches the user on the connection from the user that created the connection (DBUser1) to a new user (DBUser2). Authenticating users with Kerberos is common in reauthentication scenarios, but is not required.
connection.ConnectionString = "Authentication Method=Kerberos;ReAuthentication Enabled=true; ... ";
 
connection.Open();
 
// Perform work as the user authenticated via Kerberos
 
connection.Close();
 
connection.CurrentUser = "DBUser1";
connection.CurrentPassword = "******";
 
// The connection is ReAuthenticated as DBUser1
connection.Open();
 
// Perform work as DBUser1
 
connection.Close();
 
connection.CurrentUser = "DBUser2";
connection.CurrentPassword = "******";
 
// The connection is Reauthenticated as DBUser2
connection.Open();
 
// Perform work as DBUser2
See the individual data provider chapters for information on the options that are supported for each data provider.
See “Authentication” for more information about using security with the DataDirect data providers.
Handling Distributed Transactions in a Pool
The Pool Manager groups the connections according to the requirement for transactions. If the requesting thread requires a specific transaction context, it must be matched to a connection with the same transaction context, for example, a connection that has been enlisted in distributed transactions.
Because closed connections are returned to the appropriate connection pool, you can close a connection even though a distributed transaction is pending. This means that you can still commit or roll back the distributed transaction until the connection is closed at the server.
See “Using Distributed Transactions” for more information about how the data providers process distributed transactions.
Tracking Connection Performance
All DataDirect Connect for ADO.NET data providers include counters that let you debug and tune the connection performance of applications that use the data provider.
See “Analyzing Performance With Connection Statistics” for information about using run-time statistics to get a snapshot-in-time of a connection’s behavior.
See “PerfMon Support” for information about using the PerfMon counters.