@@ -10,7 +10,7 @@ namespace MySql.Data.MySqlClient
10
10
{
11
11
internal sealed class ConnectionPool
12
12
{
13
- public async Task < MySqlSession > GetSessionAsync ( IOBehavior ioBehavior , CancellationToken cancellationToken )
13
+ public async Task < MySqlSession > GetSessionAsync ( MySqlConnection connection , IOBehavior ioBehavior , CancellationToken cancellationToken )
14
14
{
15
15
cancellationToken . ThrowIfCancellationRequested ( ) ;
16
16
@@ -54,17 +54,19 @@ public async Task<MySqlSession> GetSessionAsync(IOBehavior ioBehavior, Cancellat
54
54
}
55
55
56
56
// pooled session is ready to be used; return it
57
+ session . OwningConnection = new WeakReference < MySqlConnection > ( connection ) ;
57
58
lock ( m_leasedSessions )
58
- m_leasedSessions . Add ( session . Id , new WeakReference < MySqlSession > ( session ) ) ;
59
+ m_leasedSessions . Add ( session . Id , session ) ;
59
60
return session ;
60
61
}
61
62
}
62
63
63
64
// create a new session
64
65
session = new MySqlSession ( this , m_generation , Interlocked . Increment ( ref m_lastId ) ) ;
65
66
await session . ConnectAsync ( m_connectionSettings , ioBehavior , cancellationToken ) . ConfigureAwait ( false ) ;
67
+ session . OwningConnection = new WeakReference < MySqlConnection > ( connection ) ;
66
68
lock ( m_leasedSessions )
67
- m_leasedSessions . Add ( session . Id , new WeakReference < MySqlSession > ( session ) ) ;
69
+ m_leasedSessions . Add ( session . Id , session ) ;
68
70
return session ;
69
71
}
70
72
catch
@@ -95,6 +97,7 @@ public void Return(MySqlSession session)
95
97
{
96
98
lock ( m_leasedSessions )
97
99
m_leasedSessions . Remove ( session . Id ) ;
100
+ session . OwningConnection = null ;
98
101
if ( SessionIsHealthy ( session ) )
99
102
lock ( m_sessions )
100
103
m_sessions . AddFirst ( session ) ;
@@ -111,6 +114,7 @@ public async Task ClearAsync(IOBehavior ioBehavior, CancellationToken cancellati
111
114
{
112
115
// increment the generation of the connection pool
113
116
Interlocked . Increment ( ref m_generation ) ;
117
+ RecoverLeakedSessions ( ) ;
114
118
await CleanPoolAsync ( ioBehavior , session => session . PoolGeneration != m_generation , false , cancellationToken ) . ConfigureAwait ( false ) ;
115
119
}
116
120
@@ -123,27 +127,25 @@ public async Task ReapAsync(IOBehavior ioBehavior, CancellationToken cancellatio
123
127
}
124
128
125
129
/// <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.
130
133
/// </summary>
131
134
private void RecoverLeakedSessions ( )
132
135
{
133
- var recoveredIds = new List < int > ( ) ;
136
+ var recoveredSessions = new List < MySqlSession > ( ) ;
134
137
lock ( m_leasedSessions )
135
138
{
136
139
m_lastRecoveryTime = unchecked ( ( uint ) Environment . TickCount ) ;
137
140
foreach ( var pair in m_leasedSessions )
138
141
{
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 ) ;
141
145
}
142
- foreach ( var id in recoveredIds )
143
- m_leasedSessions . Remove ( id ) ;
144
146
}
145
- if ( recoveredIds . Count > 0 )
146
- m_sessionSemaphore . Release ( recoveredIds . Count ) ;
147
+ foreach ( var session in recoveredSessions )
148
+ session . ReturnToPool ( ) ;
147
149
}
148
150
149
151
private async Task CleanPoolAsync ( IOBehavior ioBehavior , Func < MySqlSession , bool > shouldCleanFn , bool respectMinPoolSize , CancellationToken cancellationToken )
@@ -250,7 +252,7 @@ private ConnectionPool(ConnectionSettings cs)
250
252
m_cleanSemaphore = new SemaphoreSlim ( 1 ) ;
251
253
m_sessionSemaphore = new SemaphoreSlim ( cs . MaximumPoolSize ) ;
252
254
m_sessions = new LinkedList < MySqlSession > ( ) ;
253
- m_leasedSessions = new Dictionary < int , WeakReference < MySqlSession > > ( ) ;
255
+ m_leasedSessions = new Dictionary < int , MySqlSession > ( ) ;
254
256
}
255
257
256
258
static readonly ConcurrentDictionary < string , ConnectionPool > s_pools = new ConcurrentDictionary < string , ConnectionPool > ( ) ;
@@ -280,7 +282,7 @@ private ConnectionPool(ConnectionSettings cs)
280
282
readonly SemaphoreSlim m_sessionSemaphore ;
281
283
readonly LinkedList < MySqlSession > m_sessions ;
282
284
readonly ConnectionSettings m_connectionSettings ;
283
- readonly Dictionary < int , WeakReference < MySqlSession > > m_leasedSessions ;
285
+ readonly Dictionary < int , MySqlSession > m_leasedSessions ;
284
286
int m_lastId ;
285
287
uint m_lastRecoveryTime ;
286
288
}
0 commit comments