Microsoft.Data.SqlClient.ConnectionPool.WaitHandleDbConnectionPool
A concrete implementation of IDbConnectionPool used by Microsoft.Data.SqlClient
to efficiently manage a pool of reusable DbConnectionInternal objects backing ADO.NET SqlConnection instances.
Primary Responsibilities:
Connection Reuse and Pooling: Uses two stacks (_stackNew and _stackOld) to manage idle connections. Ensures efficient reuse and limits new connection creation.Transaction-Aware Pooling: Tracks connections enlisted in Transaction using TransactedConnectionPool and TransactedConnectionList, ensuring proper context reuse.Concurrency and Synchronization: Uses wait handles and semaphores via PoolWaitHandles to coordinate safe multi-threaded access.Connection Lifecycle Management: Manages creation (CreateObject), deactivation (DeactivateObject), destruction (DestroyObject), and reclamation (ReclaimEmancipatedObjects) of internal connections.Error Handling and Resilience: Implements retry and exponential backoff in TryGetConnection and handles transient errors using _errorWait.Minimum Pool Size Enforcement: Maintains the MinPoolSize by spawning background tasks to create new connections when needed.Load Balancing Support: Honors LoadBalanceTimeout to clean up idle connections and distribute load evenly.Telemetry and Tracing: Uses SqlClientEventSource for extensive diagnostic tracing of connection lifecycle events.Pending Request Queue: Queues unresolved connection requests in _pendingOpens and processes them using background threads.Identity and Authentication Context: Manages identity-based reuse via a dictionary of DbConnectionPoolAuthenticationContext keyed by user identity.Key Concepts in Design:
Stacks and queues for free and pending connectionsSynchronization via WaitHandle, Semaphore, and ManualResetEventSupport for transaction enlistment and affinityTimer-based cleanup to prune idle or expired connectionsBackground thread spawning for servicing deferred requests and replenishing the poolnamespace Microsoft.Data.SqlClient.ConnectionPool
{
internal sealed class WaitHandleDbConnectionPool : IDbConnectionPool
{
public int Id { get; }
public DbConnectionPoolState State { get; set; }
public int Count { get; }
public int IdleCount { get; }
public SqlConnectionFactory ConnectionFactory { get; }
public bool ErrorOccurred { get; }
public TimeSpan LoadBalanceTimeout { get; }
public DbConnectionPoolIdentity Identity { get; }
public bool IsRunning { get; }
public DbConnectionPoolGroup PoolGroup { get; }
public DbConnectionPoolGroupOptions PoolGroupOptions { get; }
public DbConnectionPoolProviderInfo ProviderInfo { get; }
public ConcurrentDictionary<DbConnectionPoolAuthenticationContextKey, DbConnectionPoolAuthenticationContext> AuthenticationContexts { get; }
public bool UseLoadBalancing { get; }
public TransactedConnectionPool TransactedConnectionPool { get; }
public void Clear();
public bool TryGetConnection(DbConnection owningObject, TaskCompletionSource<DbConnectionInternal> taskCompletionSource, DbConnectionOptions userOptions, out DbConnectionInternal connection);
public DbConnectionInternal ReplaceConnection(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection);
public void ReturnInternalConnection(DbConnectionInternal obj, DbConnection owningObject);
public void PutObjectFromTransactedPool(DbConnectionInternal obj);
public void Startup();
public void Shutdown();
public void TransactionEnded(Transaction transaction, DbConnectionInternal transactedObject);
}
}