@@ -10,7 +10,7 @@ namespace MySql.Data.MySqlClient
1010{
1111 internal sealed class ConnectionPool
1212 {
13- public async Task < MySqlSession > GetSessionAsync ( IOBehavior ioBehavior , CancellationToken cancellationToken )
13+ public async Task < MySqlSession > GetSessionAsync ( MySqlConnection connection , IOBehavior ioBehavior , CancellationToken cancellationToken )
1414 {
1515 cancellationToken . ThrowIfCancellationRequested ( ) ;
1616
@@ -54,17 +54,19 @@ public async Task<MySqlSession> GetSessionAsync(IOBehavior ioBehavior, Cancellat
5454 }
5555
5656 // pooled session is ready to be used; return it
57+ session . OwningConnection = new WeakReference < MySqlConnection > ( connection ) ;
5758 lock ( m_leasedSessions )
58- m_leasedSessions . Add ( session . Id , new WeakReference < MySqlSession > ( session ) ) ;
59+ m_leasedSessions . Add ( session . Id , session ) ;
5960 return session ;
6061 }
6162 }
6263
6364 // create a new session
6465 session = new MySqlSession ( this , m_generation , Interlocked . Increment ( ref m_lastId ) ) ;
6566 await session . ConnectAsync ( m_connectionSettings , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
67+ session . OwningConnection = new WeakReference < MySqlConnection > ( connection ) ;
6668 lock ( m_leasedSessions )
67- m_leasedSessions . Add ( session . Id , new WeakReference < MySqlSession > ( session ) ) ;
69+ m_leasedSessions . Add ( session . Id , session ) ;
6870 return session ;
6971 }
7072 catch
@@ -95,6 +97,7 @@ public void Return(MySqlSession session)
9597 {
9698 lock ( m_leasedSessions )
9799 m_leasedSessions . Remove ( session . Id ) ;
100+ session . OwningConnection = null ;
98101 if ( SessionIsHealthy ( session ) )
99102 lock ( m_sessions )
100103 m_sessions . AddFirst ( session ) ;
@@ -111,6 +114,7 @@ public async Task ClearAsync(IOBehavior ioBehavior, CancellationToken cancellati
111114 {
112115 // increment the generation of the connection pool
113116 Interlocked . Increment ( ref m_generation ) ;
117+ RecoverLeakedSessions ( ) ;
114118 await CleanPoolAsync ( ioBehavior , session => session . PoolGeneration != m_generation , false , cancellationToken ) . ConfigureAwait ( false ) ;
115119 }
116120
@@ -123,27 +127,25 @@ public async Task ReapAsync(IOBehavior ioBehavior, CancellationToken cancellatio
123127 }
124128
125129 /// <summary>
126- /// Examines all the <see cref="WeakReference{MySqlSession}"/> in <see cref="m_leasedSessions"/> to determine if any
127- /// <see cref="MySqlSession"/> objects have been garbage-collected. If so, assumes that the related <see cref="MySqlConnection"/>
128- /// was not properly disposed but the associated server connection has been closed (by the finalizer). Releases the semaphore
129- /// once for each leaked session to allow new client connections to be made.
130+ /// Examines all the <see cref="MySqlSession"/> objects in <see cref="m_leasedSessions"/> to determine if any
131+ /// have an owning <see cref="MySqlConnection"/> that has been garbage-collected. If so, assumes that the connection
132+ /// was not properly disposed and returns the session to the pool.
130133 /// </summary>
131134 private void RecoverLeakedSessions ( )
132135 {
133- var recoveredIds = new List < int > ( ) ;
136+ var recoveredSessions = new List < MySqlSession > ( ) ;
134137 lock ( m_leasedSessions )
135138 {
136139 m_lastRecoveryTime = unchecked ( ( uint ) Environment . TickCount ) ;
137140 foreach ( var pair in m_leasedSessions )
138141 {
139- if ( ! pair . Value . TryGetTarget ( out var _ ) )
140- recoveredIds . Add ( pair . Key ) ;
142+ var session = pair . Value ;
143+ if ( ! session . OwningConnection . TryGetTarget ( out var _ ) )
144+ recoveredSessions . Add ( session ) ;
141145 }
142- foreach ( var id in recoveredIds )
143- m_leasedSessions . Remove ( id ) ;
144146 }
145- if ( recoveredIds . Count > 0 )
146- m_sessionSemaphore . Release ( recoveredIds . Count ) ;
147+ foreach ( var session in recoveredSessions )
148+ session . ReturnToPool ( ) ;
147149 }
148150
149151 private async Task CleanPoolAsync ( IOBehavior ioBehavior , Func < MySqlSession , bool > shouldCleanFn , bool respectMinPoolSize , CancellationToken cancellationToken )
@@ -250,7 +252,7 @@ private ConnectionPool(ConnectionSettings cs)
250252 m_cleanSemaphore = new SemaphoreSlim ( 1 ) ;
251253 m_sessionSemaphore = new SemaphoreSlim ( cs . MaximumPoolSize ) ;
252254 m_sessions = new LinkedList < MySqlSession > ( ) ;
253- m_leasedSessions = new Dictionary < int , WeakReference < MySqlSession > > ( ) ;
255+ m_leasedSessions = new Dictionary < int , MySqlSession > ( ) ;
254256 }
255257
256258 static readonly ConcurrentDictionary < string , ConnectionPool > s_pools = new ConcurrentDictionary < string , ConnectionPool > ( ) ;
@@ -280,7 +282,7 @@ private ConnectionPool(ConnectionSettings cs)
280282 readonly SemaphoreSlim m_sessionSemaphore ;
281283 readonly LinkedList < MySqlSession > m_sessions ;
282284 readonly ConnectionSettings m_connectionSettings ;
283- readonly Dictionary < int , WeakReference < MySqlSession > > m_leasedSessions ;
285+ readonly Dictionary < int , MySqlSession > m_leasedSessions ;
284286 int m_lastId ;
285287 uint m_lastRecoveryTime ;
286288 }
0 commit comments