Skip to content

Commit 583be72

Browse files
committed
Make sure MySqlConnection isn't GCed.
If the MySqlConnection associated with the ServerSession was garbage collected, then the ServerSession could inaccurately be detected as being leaked, even though it's being reset about about to be returned to the pool.
1 parent 3f9cc2c commit 583be72

File tree

4 files changed

+16
-16
lines changed

4 files changed

+16
-16
lines changed

src/MySqlConnector/Core/BackgroundConnectionResetHelper.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ namespace MySqlConnector.Core
99
{
1010
internal static class BackgroundConnectionResetHelper
1111
{
12-
public static void AddSession(ServerSession session)
12+
public static void AddSession(ServerSession session, MySqlConnection? owningConnection)
1313
{
14-
// TODO: save the MySqlConnection object so this session isn't considered leaked
15-
1614
var resetTask = session.TryResetConnectionAsync(session.Pool!.ConnectionSettings, IOBehavior.Asynchronous, default);
1715
lock (s_lock)
18-
s_sessions.Add(new SessionResetTask(session, resetTask));
16+
s_sessions.Add(new SessionResetTask(session, resetTask, owningConnection));
1917

2018
if (Log.IsDebugEnabled())
2119
Log.Debug("Started Session{0} reset in background; waiting SessionCount: {1}.", session.Id, s_sessions.Count);
@@ -71,7 +69,7 @@ public static async Task ReturnSessionsAsync()
7169
Log.Info("Started BackgroundConnectionResetHelper worker.");
7270

7371
List<Task<bool>> localTasks = new();
74-
List<ServerSession> localSessions = new();
72+
List<SessionResetTask> localSessions = new();
7573

7674
// keep running until stopped
7775
while (!s_cancellationTokenSource.IsCancellationRequested)
@@ -94,10 +92,10 @@ public static async Task ReturnSessionsAsync()
9492
}
9593
else
9694
{
97-
foreach (var data in s_sessions)
95+
foreach (var session in s_sessions)
9896
{
99-
localSessions.Add(data.Session);
100-
localTasks.Add(data.ResetTask);
97+
localSessions.Add(session);
98+
localTasks.Add(session.ResetTask);
10199
}
102100
s_sessions.Clear();
103101
}
@@ -110,7 +108,7 @@ public static async Task ReturnSessionsAsync()
110108
{
111109
var completedTask = await Task.WhenAny(localTasks).ConfigureAwait(false);
112110
var index = localTasks.IndexOf(completedTask);
113-
var session = localSessions[index];
111+
var session = localSessions[index].Session;
114112
await session.Pool!.ReturnAsync(IOBehavior.Asynchronous, session).ConfigureAwait(false);
115113
localSessions.RemoveAt(index);
116114
localTasks.RemoveAt(index);
@@ -126,21 +124,23 @@ public static async Task ReturnSessionsAsync()
126124

127125
internal struct SessionResetTask
128126
{
129-
public SessionResetTask(ServerSession session, Task<bool> resetTask)
127+
public SessionResetTask(ServerSession session, Task<bool> resetTask, MySqlConnection? owningConnection)
130128
{
131129
Session = session;
132130
ResetTask = resetTask;
131+
OwningConnection = owningConnection;
133132
}
134133

135134
public ServerSession Session { get; }
136135
public Task<bool> ResetTask { get; }
136+
public MySqlConnection? OwningConnection { get; }
137137
}
138138

139139
static readonly IMySqlConnectorLogger Log = MySqlConnectorLogManager.CreateLogger(nameof(BackgroundConnectionResetHelper));
140140
static readonly object s_lock = new();
141141
static readonly SemaphoreSlim s_semaphore = new(1, 1);
142142
static readonly CancellationTokenSource s_cancellationTokenSource = new();
143-
static List<SessionResetTask> s_sessions = new();
143+
static readonly List<SessionResetTask> s_sessions = new();
144144
static Task? s_workerTask;
145145
}
146146
}

src/MySqlConnector/Core/ConnectionPool.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ private async Task RecoverLeakedSessionsAsync(IOBehavior ioBehavior)
249249
else
250250
Log.Warn("Pool{0}: RecoveredSessionCount={1}", m_logArguments[0], recoveredSessions.Count);
251251
foreach (var session in recoveredSessions)
252-
await session.ReturnToPoolAsync(ioBehavior).ConfigureAwait(false);
252+
await session.ReturnToPoolAsync(ioBehavior, null).ConfigureAwait(false);
253253
}
254254

255255
private async Task CleanPoolAsync(IOBehavior ioBehavior, Func<ServerSession, bool> shouldCleanFn, bool respectMinPoolSize, CancellationToken cancellationToken)

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public ServerSession(ConnectionPool? pool, int poolGeneration, int id)
6868
public bool SupportsSessionTrack => m_supportsSessionTrack;
6969
public bool ProcAccessDenied { get; set; }
7070

71-
public Task ReturnToPoolAsync(IOBehavior ioBehavior)
71+
public Task ReturnToPoolAsync(IOBehavior ioBehavior, MySqlConnection? owningConnection)
7272
{
7373
if (Log.IsDebugEnabled())
7474
{
@@ -80,7 +80,7 @@ public Task ReturnToPoolAsync(IOBehavior ioBehavior)
8080
return Utility.CompletedTask;
8181
if (!Pool.ConnectionSettings.ConnectionReset || Pool.ConnectionSettings.DeferConnectionReset)
8282
return Pool.ReturnAsync(ioBehavior, this);
83-
BackgroundConnectionResetHelper.AddSession(this);
83+
BackgroundConnectionResetHelper.AddSession(this, owningConnection);
8484
return Utility.CompletedTask;
8585
}
8686

src/MySqlConnector/MySqlConnection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,7 +925,7 @@ m_enlistedTransaction is null &&
925925
m_cachedProcedures = null;
926926
if (m_session is not null)
927927
{
928-
await m_session.ReturnToPoolAsync(ioBehavior).ConfigureAwait(false);
928+
await m_session.ReturnToPoolAsync(ioBehavior, this).ConfigureAwait(false);
929929
m_session = null;
930930
}
931931
if (changeState)
@@ -994,7 +994,7 @@ private async Task DoCloseAsync(bool changeState, IOBehavior ioBehavior)
994994
{
995995
if (GetInitializedConnectionSettings().Pooling)
996996
{
997-
await m_session.ReturnToPoolAsync(ioBehavior).ConfigureAwait(false);
997+
await m_session.ReturnToPoolAsync(ioBehavior, this).ConfigureAwait(false);
998998
}
999999
else
10001000
{

0 commit comments

Comments
 (0)