"System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool."(转)

 
 

Another post on the following exception:

System.InvalidOperationException: Timeout expired.  The timeout period elapsed prior to obtaining a connection from the pool.
This may have occurred because all pooled connections were in use and max pool size was reached.
   at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
   at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
   at System.Data.SqlClient.SqlConnection.Open()

Basically this means that the connection pool is full and that all connections are in use. Which we can see from the text in the exception J
However, sometimes you may not have the source code but still need to figure out what the connection pool settings and state is.
 
So, the premise here is that you have an application that sometimes fails with the exception above and you do not have the source but you wish
to figure out what the max and min pool sizes are and what the current number of connections in the pool is.
 
Start by creating a simple command prompt application that connects to a SQL Server (code below is to provoke the exception and do not reflect
any recommendation on how to program database connections).

namespace PoolExhaust
{
    class Program
    {
        static void Main(string[] args)
        {
            string connString = @"Data Source=<your server>;Initial Catalog=<your database>;Integrated Security=True; Max Pool Size=20; Connection Timeout=10";
            try
            {
                for (int i = 0; i < 50; i++)
                {
                    SqlConnection sc = new SqlConnection(connString);
                    SqlCommand sCmd = new SqlCommand("SELECT * FROM <your table>", sc);
                    sc.Open();
                    Console.WriteLine("Connections open: {0}", i.ToString());
                    SqlDataReader sdr = sCmd.ExecuteReader();
                    sdr.Close();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
        }
    }
}

Build it and run it to confirm that you get the exception.
Now, since we do not have the source code (in theory) we should generate a dump. Assuming that we are on Windows 2008 or 7 you can simply start the Task Manager and then run the application again.
When it is running, right click the application in Task Manager and select “Create Dump File”. Take note of where it is stored, should be in the C:\Users\...
 
Open the dump in WinDbg and load the SOS extension suitable for your application.

0:000> .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll

Now, what we want to know is what the max and min pool size is for the connection pool and what the current number of connections in the pool is.
So we will start with getting the DbConnectionPool.

0:000> !dumpheap -stat -type System.Data.ProviderBase.DbConnectionPool
total 0 objects
Statistics:
              MT    Count    TotalSize Class Name
…
000007fee3653dc0        1          176 System.Data.ProviderBase.DbConnectionPool
…

Then use the MT to get the address:

0:000> !dumpheap -mt 000007fee3653dc0      
         Address               MT     Size
0000000002db24c0 000007fee3653dc0      176

and then dump the address:

0:000> !do 0000000002db24c0
Name:        System.Data.ProviderBase.DbConnectionPool
MethodTable: 000007fee3653dc0
EEClass:     000007fee34d26f8
Size:        176(0xb0) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fee5e9c610  4001579       88         System.Int32  1 instance           190000 _cleanupWait
000007fee3652e80  400157a        8 ...ctionPoolIdentity  0 instance 0000000002db24a0 _identity
000007fee36535f0  400157b       10 ...ConnectionFactory  0 instance 0000000002d8dfb8 _connectionFactory
000007fee3653700  400157c       18 ...nnectionPoolGroup  0 instance 0000000002db0bb0 _connectionPoolGroup
000007fee36546d0  400157d       20 ...nPoolGroupOptions  0 instance 0000000002db0b88 _connectionPoolGroupOptions
000007fee3b82610  400157e       28 ...nPoolProviderInfo  0 instance 0000000000000000 _connectionPoolProviderInfo
…
000007fee5e9c610  400158e       98         System.Int32  1 instance               20 _totalObjects
…

Here you will see _totalObjects. This is the number of connections in the pool, which happens to be 20 in this case. Then dump the _connectionPoolGroupOptions:

0:000> !do 0000000002db0b88
Name:        System.Data.ProviderBase.DbConnectionPoolGroupOptions
MethodTable: 000007fee36546d0
EEClass:     000007fee34f5620
Size:        40(0x28) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fee5e9d440  40015d8       14       System.Boolean  1 instance                1 _poolByIdentity
000007fee5e9c610  40015d9        8         System.Int32  1 instance                0 _minPoolSize
000007fee5e9c610  40015da        c         System.Int32  1 instance               20 _maxPoolSize
…

Which clearly shows you the max and min pool sizes. In this case we will soon get the mentioned exception since we have 20 objects in the pool and the max is 20.
 
Now, if you wish to find out the connection string for the connections in the dump. Simply dump the SqlConnections
 

0:000> !dumpheap -type System.Data.SqlClient.SqlConnection
         Address               MT     Size
0000000002d8dfb8 000007fee36532a8       64   
0000000002db0360 000007fee36542b8      184   
…
00000000030e7928 000007fee364fba8      104 

Pick one and dump that and then check the _userConnectionOptions.

0:000> !do 00000000030e7928
Name:        System.Data.SqlClient.SqlConnection
MethodTable: 000007fee364fba8
EEClass:     000007fee34d1c38
Size:        104(0x68) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
…
000007fee36543a8  4001775       38 ...ConnectionOptions  0 instance 0000000002db0360 _userConnectionOptions
000007fee3653700  4001776       40 ...nnectionPoolGroup  0 instance 0000000002db0bb0 _poolGroup
…
0:000> !do 0000000002db0360
Name:        System.Data.SqlClient.SqlConnectionString
MethodTable: 000007fee36542b8
EEClass:     000007fee34f53b0
Size:        184(0xb8) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fee5e96728  4000c17        8        System.String  0 instance 0000000002d8de10 _usersConnectionString
…

As we can see, luckily for us, this have a _usersConnectionString. Simply dump that:

0:000> !do 0000000002d8de10
Name:        System.String
MethodTable: 000007fee5e96728
EEClass:     000007fee5a1ed68
Size:        256(0x100) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      Data Source=<server>;Initial Catalog=<database>;Integrated Security=True; Max Pool Size=20; Connection Timeout=10

And you will see the connection string. Which again confirms what we found on the connection pool object.(这里,如果数据库连接字符串有有数据库的登录用户名和密码,也会被dump出来,嘿嘿~~~YY...)
 
So, this post is about how to find these values when you do not have the source but the possibility to take a dump on the process.
For reasons, and possible, and solutions. See a previous post here:

“Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool.”

http://blogs.msdn.com/b/spike/archive/2008/08/25/timeout-expired-the-timeout-period-elapsed-prior-to-obtaining-a-connection-from-the-pool.aspx

 
posted @ 2012-08-28 14:28  赤脚的懒虫  阅读(1373)  评论(0编辑  收藏  举报