Skip to content

Commit 14d90bb

Browse files
committed
Add ConnectionIdlePingTime setting.
This allows clients to opt-out of pinging the server when a connection is retrieved from the pool, if it's been idle less than a certain amount of time.
1 parent 2b4af5b commit 14d90bb

File tree

5 files changed

+34
-1
lines changed

5 files changed

+34
-1
lines changed

docs/content/connection-options.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,19 @@ Connection pooling is enabled by default. These options are used to configure it
117117
<td><code>true</code></td>
118118
<td>If <code>true</code>, the connection state is reset when it is retrieved from the pool. The default value of <code>true</code> ensures that the connection is in the same state whether it's newly created or retrieved from the pool. A value of <code>false</code> avoids making an additional server round trip when obtaining a connection, but the connection state is not reset, meaning that session variables and other session state changes from any previous use of the connection are carried over.</td>
119119
</tr>
120+
<tr>
121+
<td>Connection Idle Ping Time, Connection Idle Ping Time <em>(Experimental)</em></td>
122+
<td>0</td>
123+
<td>When a connection is retrieved from the pool, and <code>ConnectionReset</code> is <code>false</code>, the server
124+
will be pinged if the connection has been idle in the pool for longer than <code>ConnectionIdlePingTime</code> seconds.
125+
If pinging the server fails, a new connection will be opened automatically by the connection pool. This ensures that the
126+
<code>MySqlConnection</code> is in a valid, open state after the call to <code>Open</code>/<code>OpenAsync</code>,
127+
at the cost of an extra server roundtrip. For high-performance scenarios, you may wish to set <code>ConnectionIdlePingTime</code>
128+
to a non-zero value to make the connection pool assume that recently-returned connections are still open. If the
129+
connection is broken, it will throw from the first call to <code>ExecuteNonQuery</code>, <code>ExecuteReader</code>,
130+
etc.; your code should handle that failure and retry the connection. This option has no effect if <code>ConnectionReset</code>
131+
is <code>true</code>, as that will cause a connection reset packet to be sent to the server, making ping redundant.
132+
</tr>
120133
<tr>
121134
<td>Connection Idle Timeout, ConnectionIdleTimeout</td>
122135
<td>180</td>

src/MySqlConnector/Core/ConnectionPool.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,14 @@ public async ValueTask<ServerSession> GetSessionAsync(MySqlConnection connection
6868
{
6969
reuseSession = await session.TryResetConnectionAsync(ConnectionSettings, ioBehavior, cancellationToken).ConfigureAwait(false);
7070
}
71-
else
71+
else if ((unchecked((uint) Environment.TickCount) - session.LastReturnedTicks) > ConnectionSettings.ConnectionIdlePingTime)
7272
{
7373
reuseSession = await session.TryPingAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
7474
}
75+
else
76+
{
77+
reuseSession = true;
78+
}
7579
}
7680

7781
if (!reuseSession)

src/MySqlConnector/Core/ConnectionSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public ConnectionSettings(MySqlConnectionStringBuilder csb)
4242
Pooling = csb.Pooling;
4343
ConnectionLifeTime = Math.Min(csb.ConnectionLifeTime, uint.MaxValue / 1000) * 1000;
4444
ConnectionReset = csb.ConnectionReset;
45+
ConnectionIdlePingTime = Math.Min(csb.ConnectionIdlePingTime, uint.MaxValue / 1000) * 1000;
4546
ConnectionIdleTimeout = (int)csb.ConnectionIdleTimeout;
4647
if (csb.MinimumPoolSize > csb.MaximumPoolSize)
4748
throw new MySqlException("MaximumPoolSize must be greater than or equal to MinimumPoolSize");
@@ -92,6 +93,7 @@ public ConnectionSettings(MySqlConnectionStringBuilder csb)
9293
public bool Pooling { get; }
9394
public uint ConnectionLifeTime { get; }
9495
public bool ConnectionReset { get; }
96+
public uint ConnectionIdlePingTime { get; }
9597
public int ConnectionIdleTimeout { get; }
9698
public int MinimumPoolSize { get; }
9799
public int MaximumPoolSize { get; }

src/MySqlConnector/MySql.Data.MySqlClient/MySqlConnectionStringBuilder.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ public bool ConnectionReset
9898
set => MySqlConnectionStringOption.ConnectionReset.SetValue(this, value);
9999
}
100100

101+
public uint ConnectionIdlePingTime
102+
{
103+
get => MySqlConnectionStringOption.ConnectionIdlePingTime.GetValue(this);
104+
set => MySqlConnectionStringOption.ConnectionIdlePingTime.SetValue(this, value);
105+
}
106+
101107
public uint ConnectionIdleTimeout
102108
{
103109
get => MySqlConnectionStringOption.ConnectionIdleTimeout.GetValue(this);
@@ -270,6 +276,7 @@ internal abstract class MySqlConnectionStringOption
270276
public static readonly MySqlConnectionStringOption<bool> Pooling;
271277
public static readonly MySqlConnectionStringOption<uint> ConnectionLifeTime;
272278
public static readonly MySqlConnectionStringOption<bool> ConnectionReset;
279+
public static readonly MySqlConnectionStringOption<uint> ConnectionIdlePingTime;
273280
public static readonly MySqlConnectionStringOption<uint> ConnectionIdleTimeout;
274281
public static readonly MySqlConnectionStringOption<uint> MinimumPoolSize;
275282
public static readonly MySqlConnectionStringOption<uint> MaximumPoolSize;
@@ -372,6 +379,10 @@ static MySqlConnectionStringOption()
372379
keys: new[] { "Connection Reset", "ConnectionReset" },
373380
defaultValue: true));
374381

382+
AddOption(ConnectionIdlePingTime = new MySqlConnectionStringOption<uint>(
383+
keys: new[] { "Connection Idle Ping Time", "ConnectionIdlePingTime" },
384+
defaultValue: 0));
385+
375386
AddOption(ConnectionIdleTimeout = new MySqlConnectionStringOption<uint>(
376387
keys: new[] { "Connection Idle Timeout", "ConnectionIdleTimeout" },
377388
defaultValue: 180));

tests/MySqlConnector.Tests/MySqlConnectionStringBuilderTests.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public void Defaults()
2929
Assert.Equal("", csb.Database);
3030
Assert.Equal(30u, csb.DefaultCommandTimeout);
3131
#if !BASELINE
32+
Assert.Equal(0u, csb.ConnectionIdlePingTime);
3233
Assert.Equal(180u, csb.ConnectionIdleTimeout);
3334
Assert.False(csb.ForceSynchronous);
3435
Assert.Null(csb.CACertificateFile);
@@ -76,6 +77,7 @@ public void ParseConnectionString()
7677
"Convert Zero Datetime=true;" +
7778
"default command timeout=123;" +
7879
#if !BASELINE
80+
"connection idle ping time=60;" +
7981
"connectionidletimeout=30;" +
8082
"forcesynchronous=true;" +
8183
"ca certificate file=ca.pem;" +
@@ -108,6 +110,7 @@ public void ParseConnectionString()
108110
Assert.Equal("schema_name", csb.Database);
109111
Assert.Equal(123u, csb.DefaultCommandTimeout);
110112
#if !BASELINE
113+
Assert.Equal(60u, csb.ConnectionIdlePingTime);
111114
Assert.Equal(30u, csb.ConnectionIdleTimeout);
112115
Assert.True(csb.ForceSynchronous);
113116
Assert.Equal("ca.pem", csb.CACertificateFile);

0 commit comments

Comments
 (0)