Skip to content

Commit 6d93fa8

Browse files
committed
Remove Func allocation when creating a ServerSession.
Introduce IConnectionPoolMetadata to unify the code between pooled and non-pooled sessions. Signed-off-by: Bradley Grainger <[email protected]>
1 parent c8a0b63 commit 6d93fa8

File tree

5 files changed

+67
-33
lines changed

5 files changed

+67
-33
lines changed

src/MySqlConnector/Core/ConnectionPool.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88

99
namespace MySqlConnector.Core;
1010

11-
internal sealed class ConnectionPool : IDisposable
11+
internal sealed class ConnectionPool : IConnectionPoolMetadata, IDisposable
1212
{
1313
public int Id { get; }
1414

15+
ConnectionPool? IConnectionPoolMetadata.ConnectionPool => this;
16+
17+
int IConnectionPoolMetadata.Generation => m_generation;
18+
19+
int IConnectionPoolMetadata.GetNewSessionId() => Interlocked.Increment(ref m_lastSessionId);
20+
1521
public string? Name { get; }
1622

1723
public ConnectionSettings ConnectionSettings { get; }
@@ -107,11 +113,8 @@ public async ValueTask<ServerSession> GetSessionAsync(MySqlConnection connection
107113
}
108114

109115
// create a new session
110-
session = await ServerSession.ConnectAndRedirectAsync(
111-
() => new ServerSession(m_connectionLogger, this, m_generation,
112-
Interlocked.Increment(ref m_lastSessionId)), m_logger, Id, ConnectionSettings, m_loadBalancer,
113-
connection, s_createdNewSession, startingTimestamp, activity, ioBehavior, cancellationToken)
114-
.ConfigureAwait(false);
116+
session = await ServerSession.ConnectAndRedirectAsync(m_connectionLogger, m_logger, this, ConnectionSettings, m_loadBalancer,
117+
connection, s_createdNewSession, startingTimestamp, activity, ioBehavior, cancellationToken).ConfigureAwait(false);
115118
AdjustHostConnectionCount(session, 1);
116119
session.OwningConnection = new(connection);
117120
int leasedSessionsCountNew;
@@ -407,11 +410,8 @@ private async Task CreateMinimumPooledSessions(MySqlConnection connection, IOBeh
407410

408411
try
409412
{
410-
var session = await ServerSession.ConnectAndRedirectAsync(
411-
() => new ServerSession(m_connectionLogger, this, m_generation,
412-
Interlocked.Increment(ref m_lastSessionId)), m_logger, Id, ConnectionSettings, m_loadBalancer,
413-
connection, s_createdToReachMinimumPoolSize, Stopwatch.GetTimestamp(), null, ioBehavior,
414-
cancellationToken).ConfigureAwait(false);
413+
var session = await ServerSession.ConnectAndRedirectAsync(m_connectionLogger, m_logger, this, ConnectionSettings, m_loadBalancer,
414+
connection, s_createdToReachMinimumPoolSize, Stopwatch.GetTimestamp(), null, ioBehavior, cancellationToken).ConfigureAwait(false);
415415
AdjustHostConnectionCount(session, 1);
416416
lock (m_sessions)
417417
_ = m_sessions.AddFirst(session);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
namespace MySqlConnector.Core;
2+
3+
internal interface IConnectionPoolMetadata
4+
{
5+
/// <summary>
6+
/// Returns the <see cref="ConnectionPool"/> this <see cref="IConnectionPoolMetadata"/> is associated with,
7+
/// or <c>null</c> if it represents a non-pooled connection.
8+
/// </summary>
9+
ConnectionPool? ConnectionPool { get; }
10+
11+
/// <summary>
12+
/// Returns the ID of the connection pool, or 0 if this is a non-pooled connection.
13+
/// </summary>
14+
int Id { get; }
15+
16+
/// <summary>
17+
/// Returns the generation of the connection pool, or 0 if this is a non-pooled connection.
18+
/// </summary>
19+
int Generation { get; }
20+
21+
/// <summary>
22+
/// Returns a new session ID.
23+
/// </summary>
24+
/// <returns>A new session ID.</returns>
25+
int GetNewSessionId();
26+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace MySqlConnector.Core;
2+
3+
internal sealed class NonPooledConnectionPoolMetadata : IConnectionPoolMetadata
4+
{
5+
public static IConnectionPoolMetadata Instance { get; } = new NonPooledConnectionPoolMetadata();
6+
7+
public ConnectionPool? ConnectionPool => null;
8+
public int Id => 0;
9+
public int Generation => 0;
10+
public int GetNewSessionId() => Interlocked.Increment(ref m_lastId);
11+
12+
private int m_lastId;
13+
}

src/MySqlConnector/Core/ServerSession.cs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,16 @@ namespace MySqlConnector.Core;
2525

2626
internal sealed partial class ServerSession : IServerCapabilities
2727
{
28-
public ServerSession(ILogger logger)
29-
: this(logger, null, 0, Interlocked.Increment(ref s_lastId))
30-
{
31-
}
32-
33-
public ServerSession(ILogger logger, ConnectionPool? pool, int poolGeneration, int id)
28+
public ServerSession(ILogger logger, IConnectionPoolMetadata pool)
3429
{
3530
m_logger = logger;
3631
m_lock = new();
3732
m_payloadCache = new();
38-
Id = (pool?.Id ?? 0) + "." + id;
33+
Id = pool.Id + "." + pool.GetNewSessionId();
3934
ServerVersion = ServerVersion.Empty;
4035
CreatedTimestamp = Stopwatch.GetTimestamp();
41-
Pool = pool;
42-
PoolGeneration = poolGeneration;
36+
Pool = pool.ConnectionPool;
37+
PoolGeneration = pool.Generation;
4338
HostName = "";
4439
m_activityTags = [];
4540
DataReader = new();
@@ -573,10 +568,11 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
573568
}
574569
}
575570

576-
public static async ValueTask<ServerSession> ConnectAndRedirectAsync(Func<ServerSession> createSession, ILogger logger, int? poolId, ConnectionSettings cs, ILoadBalancer? loadBalancer, MySqlConnection connection, Action<ILogger, int, string, Exception?>? logMessage, long startingTimestamp, Activity? activity, IOBehavior ioBehavior, CancellationToken cancellationToken)
571+
public static async ValueTask<ServerSession> ConnectAndRedirectAsync(ILogger connectionLogger, ILogger poolLogger, IConnectionPoolMetadata pool, ConnectionSettings cs, ILoadBalancer? loadBalancer, MySqlConnection connection, Action<ILogger, int, string, Exception?>? logMessage, long startingTimestamp, Activity? activity, IOBehavior ioBehavior, CancellationToken cancellationToken)
577572
{
578-
var session = createSession();
579-
if (poolId is not null && logger.IsEnabled(LogLevel.Debug)) logMessage!(logger, poolId.Value, session.Id, null);
573+
var session = new ServerSession(connectionLogger, pool);
574+
if (logMessage is not null && poolLogger.IsEnabled(LogLevel.Debug))
575+
logMessage(poolLogger, pool.Id, session.Id, null);
580576

581577
string? redirectionUrl;
582578
try
@@ -592,10 +588,10 @@ public static async ValueTask<ServerSession> ConnectAndRedirectAsync(Func<Server
592588
Exception? redirectionException = null;
593589
if (redirectionUrl is not null)
594590
{
595-
Log.HasServerRedirectionHeader(logger, session.Id, redirectionUrl);
591+
Log.HasServerRedirectionHeader(poolLogger, session.Id, redirectionUrl);
596592
if (cs.ServerRedirectionMode == MySqlServerRedirectionMode.Disabled)
597593
{
598-
Log.ServerRedirectionIsDisabled(logger, session.Id);
594+
Log.ServerRedirectionIsDisabled(poolLogger, session.Id);
599595
return session;
600596
}
601597

@@ -604,19 +600,19 @@ public static async ValueTask<ServerSession> ConnectAndRedirectAsync(Func<Server
604600
if (host != cs.HostNames![0] || port != cs.Port || user != cs.UserID)
605601
{
606602
var redirectedSettings = cs.CloneWith(host, port, user);
607-
Log.OpeningNewConnection(logger, host, port, user);
608-
var redirectedSession = createSession();
603+
Log.OpeningNewConnection(poolLogger, host, port, user);
604+
var redirectedSession = new ServerSession(connectionLogger, pool);
609605
try
610606
{
611607
await redirectedSession.ConnectAsync(redirectedSettings, connection, startingTimestamp, loadBalancer, activity, ioBehavior, cancellationToken).ConfigureAwait(false);
612-
Log.ClosingSessionToUseRedirectedSession(logger, session.Id, redirectedSession.Id);
608+
Log.ClosingSessionToUseRedirectedSession(poolLogger, session.Id, redirectedSession.Id);
613609
await session.DisposeAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
614610
return redirectedSession;
615611
}
616612
catch (Exception ex)
617613
{
618614
redirectionException = ex;
619-
Log.FailedToConnectRedirectedSession(logger, ex, redirectedSession.Id);
615+
Log.FailedToConnectRedirectedSession(poolLogger, ex, redirectedSession.Id);
620616
try
621617
{
622618
await redirectedSession.DisposeAsync(ioBehavior, cancellationToken).ConfigureAwait(false);
@@ -628,14 +624,14 @@ public static async ValueTask<ServerSession> ConnectAndRedirectAsync(Func<Server
628624
}
629625
else
630626
{
631-
Log.SessionAlreadyConnectedToServer(logger, session.Id);
627+
Log.SessionAlreadyConnectedToServer(poolLogger, session.Id);
632628
}
633629
}
634630
}
635631

636632
if (cs.ServerRedirectionMode == MySqlServerRedirectionMode.Required)
637633
{
638-
Log.RequiresServerRedirection(logger, session.Id);
634+
Log.RequiresServerRedirection(poolLogger, session.Id);
639635
throw new MySqlException(MySqlErrorCode.UnableToConnectToHost, "Server does not support redirection", redirectionException);
640636
}
641637
return session;
@@ -1991,7 +1987,6 @@ protected override void OnStatementBegin(int index)
19911987
private static readonly PayloadData s_sleepWithAttributesPayload = QueryPayload.Create(true, "SELECT SLEEP(0) INTO @\uE001MySqlConnector\uE001Sleep;"u8);
19921988
private static readonly PayloadData s_selectConnectionIdVersionNoAttributesPayload = QueryPayload.Create(false, "SELECT CONNECTION_ID(), VERSION();"u8);
19931989
private static readonly PayloadData s_selectConnectionIdVersionWithAttributesPayload = QueryPayload.Create(true, "SELECT CONNECTION_ID(), VERSION();"u8);
1994-
private static int s_lastId;
19951990

19961991
private readonly ILogger m_logger;
19971992
private readonly object m_lock;

src/MySqlConnector/MySqlConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,7 +1064,7 @@ private async ValueTask<ServerSession> CreateSessionAsync(ConnectionPool? pool,
10641064
// only "fail over" and "random" load balancers supported without connection pooling
10651065
var loadBalancer = connectionSettings.LoadBalance == MySqlLoadBalance.Random && connectionSettings.HostNames!.Count > 1 ?
10661066
RandomLoadBalancer.Instance : FailOverLoadBalancer.Instance;
1067-
var session = await ServerSession.ConnectAndRedirectAsync(() => new ServerSession(m_logger), m_logger, null, connectionSettings, loadBalancer, this, null, startingTimestamp, null, actualIOBehavior, connectToken).ConfigureAwait(false);
1067+
var session = await ServerSession.ConnectAndRedirectAsync(m_logger, m_logger, NonPooledConnectionPoolMetadata.Instance, connectionSettings, loadBalancer, this, null, startingTimestamp, null, actualIOBehavior, connectToken).ConfigureAwait(false);
10681068
session.OwningConnection = new WeakReference<MySqlConnection>(this);
10691069
Log.CreatedNonPooledSession(m_logger, session.Id);
10701070
return session;

0 commit comments

Comments
 (0)